1
votes

I know we can stretch item to the right or down using ColumnSpan and RowSpan

However I got an Item I want to display in grid cell and have it centered according to this cell center, so it will span both right and left in case of text, here I provide an image of how it currently looks, "12345" text can't fit the column and is displayed as "234", is there a way to make 1 & 5 visible leaving all columns untouched?enter image description here

Text can be changed to anything and has to be centered correctly, I can hack a way to display 12345 this way , but need a solution that will work with any text, just in case,and textBlock grid.Column has to be left untouched 1 (or 2 to be precise for my case) , not 0 for this picture case.

2

2 Answers

1
votes

I'm not sure I fully understand the restrictions on your problem, so it's possible that neither of these solutions will work, but here's two quick suggestions. (Personally, I like Solution 2 better.)

<Edit: Additional Thought>
Solution 0
If you're able to change the Grid.ColumnSpan of the textblock, you can do solution 2 without the container. Just span the textblock over a couple of columns and adjust the padding of the textblock to center the contents!
</Edit>

Solution 1
First off, if your current XAML structure looks something like this:

<Grid>
    <TextBlock Grid.Column="2" Text="12345" />
</Grid>

Consider changing it to something like this?

<Grid>
    <!-- Draw up columns so that the textblock looks as you wish -->
    <TextBlock Grid.Column="2" Text="12345" />

    <!-- Span an inner grid across all the columns/rows in the outer grid -->
    <Grid Grid.ColumnSpan=".." 
          Grid.RowSpan="..">
        <!-- All the other stuff in the Grid -->
    </Grid>
</Grid>

Solution 2
If that can't work, consider housing the textblock in another container such as a Label, and spanning that across the columns.

<Grid>
    <!-- Use the left/right padding on the label to center the textbox -->
    <sdk:Label Grid.Column="0"
               Grid.ColumnSpan="3"
               Grid.Row="1"
               HorizontalAlignment="Center"
               Padding="13,0,0,0">
        <!-- In my example, setting the left pading to 13 centered the textbox -->
        <TextBlock HorizontalAlignment="Center"
                   Text="......!......" />
        <!-- Text like the test above, really helped find the correct padding -->
    </sdk:Label>
</Grid>


I hope this works within your restrictions, and if not, helps you figure out a solution yourself!

1
votes

Solution 4
So what you actually want is a way to center the text dynamically if I now understand correctly. You don't want to have to work out fiddling with the padding yourself, you want a number that works for everything? I sure hope you appreciate this! :)

/// <summary>
/// Takes a FrameworkElement that is spanned across
/// multiple columns and RETURNS a Thickness that
/// can be applied to the Padding property to
/// centre it across the spanned columns
/// </summary>
/// <param name="fe">The FrameworkElement to be centred</param>
/// <param name="centerColumn">The index of the desired centre column</param>
/// <returns>A Thickness that will center the FrameworkElement</returns>
private Thickness GetCenteringPadding(FrameworkElement fe, int centerColumn)
{
    Grid parentGrid = fe.Parent as Grid;
    if (parentGrid == null)
        throw new ArgumentException();

    // Variables
    int firstColumn = (int)fe.GetValue(Grid.ColumnProperty);
    int columnSpan = (int)fe.GetValue(Grid.ColumnSpanProperty);
    double totalWidth = 0.0;
    double leftWidth = 0.0;
    double leftPaddingWidth = 0.0;

    // Total the width for all the spanned columns
    for (int i = firstColumn; i < columnSpan + firstColumn; i++)
    {
        // This part can be dangerous, especially if you're using a '*'
        totalWidth += parentGrid.ColumnDefinitions[i].ActualWidth;
    }

    // Get the total width from the left side of the first
    //  spanned column, to the center of the 'centerColumn'
    for (int j = firstColumn; j <= centerColumn; j++)
    {
        if (j != centerColumn)
            leftWidth += parentGrid.ColumnDefinitions[j].ActualWidth;
        else // Only take half the width for the center column
            leftWidth += parentGrid.ColumnDefinitions[j].ActualWidth / 2;
    }

    // Calculate the padding width
    // (Abbr. rightWidth = tW - lW, lPW = lW - rW)
    leftPaddingWidth = 2*leftWidth - totalWidth;

    // Check whether the padding needs to be on the left or the right
    if (leftPaddingWidth > 0.0)
    {
        // The excess space is on the left
        return new Thickness(leftPaddingWidth, 0.0, 0.0, 0.0);
    }
    else
    {
        // The excess space is on the right
        return new Thickness(0.0, 0.0, -leftPaddingWidth, 0.0);
    }
}

A couple of notes. It uses the .ActualWidth of the columns in the Grid. You can change this of course to .Width, however you may run into problems when you're using ColumnDefinition Width="30*" because I'm quite sure you won't get a double as the result then. Secondly, this function doesn't set the padding on the object you pass for two reasons:
- You can take the returned Thickness and add it to the .Padding already applied to a Control so that you don't destroy it's formatting.
- You can pass any FrameworkElement, whereas only Controls have padding. Perhaps you could add the returned thickness to the .Margin property instead, or even create a container and apply padding within that?
Finally, you could easily combine the two for loops within the function, but I left them seperate from clarity.
Cheers.