views:

227

answers:

3

I am trying to get a layout where an icon floats on the right end of a textblock; the textblock grows/shrinks to content. I cannot make this happen without the textblock running outside the grid. For example:

<Grid x:Name="LayoutRoot" Width="500" HorizontalAlignment="Left" ShowGridLines="True" >
 <Grid.ColumnDefinitions>
  <ColumnDefinition Width="Auto" />
  <ColumnDefinition Width="40"/>
 </Grid.ColumnDefinitions>
   <TextBlock x:Name="textBlock" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="0" >
  <TextBlock.Text>longer keeps going and going testgrand you going and then t 
</TextBlock.Text>
  </TextBlock>
<Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="1"/>
</Grid>

Seems like the natural approach and works fine when the text is shorter than the column/grid, except the textbox and column will grow indefinitely and not honor the bounds of the grid.

The inverse, with the icon on the left, works fine with a simpler layout, and the textblock doesn’t grow indefinitely. This is achieved with this markup:

<Grid Grid.Row="1" Width="500" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
  <ColumnDefinition Width="40" />
  <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41"  Width="41" Grid.Column="0"/>
  <TextBlock x:Name="textBlock2" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="1" HorizontalAlignment="Left">
  <TextBlock.Text>longer testgrow the textblock and it will just keep growing but it will stop when it gets too </TextBlock.Text>
 </TextBlock>
</Grid>

Any help appreciated. If a grid won’t work, is there an alternate layout where I can get the icon floating on the right of the text, and the textblock will trim text when it’s too long?

Also:

  • No, using * size columns doesn't work because the columns are fixed, and the icon won't float at the end of the text

  • A DockPanel doesn't work either, or at least I or others I've asked haven't been able to. The best it can do is to have the icon half-cut-off outside the dockpanel's right side.

A: 

The below code will result in the following output, is that what you are looking for???

longer keeps going and going... [red rectangle]

<Grid Width="200">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" Text="longer keeps going and going testgrand you going and then t" TextTrimming="CharacterEllipsis"/> 
    <Rectangle Grid.Column="1" Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" />
</Grid>
Wallstreet Programmer
No, it won't. The column with the textblock will be fixed. The icon will sit on the right of the grid and not float at the end of the text. Just like I said in the original question.
dex3703
+1  A: 

Can you get what you want by setting MaxWidth on the TextBlock? If you add MaxWidth="460" to your first example:

<Grid x:Name="LayoutRoot" Width="500" HorizontalAlignment="Left" ShowGridLines="True" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="40"/>
    </Grid.ColumnDefinitions>
    <TextBlock MaxWidth="460" x:Name="textBlock" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="0" >
        <TextBlock.Text>longer keeps going and going testgrand you going and then t</TextBlock.Text>
    </TextBlock>
    <Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="1"/>
</Grid>

Then the TextBlock will grow horizontally and always have the rectangle immediately on its right. It won't be wider than 460, so the TextBlock plus the Rectangle shouldn't be wider than 500. If you need the Grid to resize dynamically then you can bind TextBlock.MaxWidth to Grid.ActualWidth with a converter that subtracts the width of the Rectangle.


Edit:

Actually, it should be even simpler than that. Use star sizing on the columns, but set MaxWidth instead of Width on the Grid. That way, the grid itself will get smaller when the text is smaller so that the rectangle is always at the edge of the text.

<Grid x:Name="LayoutRoot" MaxWidth="500" HorizontalAlignment="Left" ShowGridLines="True" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="40"/>
    </Grid.ColumnDefinitions>
    <TextBlock x:Name="textBlock" VerticalAlignment="Top" Height="25" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Grid.Column="0" >
        <TextBlock.Text>longer keeps going and going testgrand you going and then t</TextBlock.Text>
    </TextBlock>
    <Rectangle Fill="#FFDE3030" Stroke="Black" VerticalAlignment="Top" Height="41" Width="41" Grid.Column="1"/>
</Grid>
Quartermeister
Thanks! I do need a fluid layout, so I'll have to figure out how to use a converter (I'm not really a dev). I did think about binding the grid's width but couldn't quite figure it out. I'll let you know if this works out! Is it just me or should this just work like I expect out of the gate? Shouldn't the textblock just stop and trim at the end of the column?!?!
dex3703
Oh, could I avoid the converter by just putting a margin on the textblock that's the width of the rectangle?
dex3703
@dex3703: You could set a right Margin on the TextBlock, right-align the Rectangle, and only have one column and you could get the same behavior. The column widths won't take into account the available space if you use Auto sizing, though, so you would still need to switch to Star sizing or set the MaxWidth of the TextBlock. See my updated answer for a simpler solution.
Quartermeister
ACtually you're incorrect...I've tried this. * columns aren't fluid. The right icon won't float on the edge of the text. Could you put the binding with the converter example back?
dex3703
@dex3703: I may not understand what you're trying to do, then. When I try it, my solution has the left edge of the Rectangle always at the right edge of the text. If the text gets shorter, the Rectangle moves left. Is that not what you see or not what you want? Star sizing will force the TextBlock to use up the remaining width of the Grid, but by setting the HorizontalAlignment to Left and leaving the Width unset, the Grid control itself will get smaller when the text is smaller.
Quartermeister
Hi Quartermeister,Someone on another team has this solution that works:<WrapPanel HorizontalAlignment="Left" VerticalAlignment="Top"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="10" /> </Grid.ColumnDefinitions> <AccessText Margin="0,0,12,0" TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.ColumnSpan="2" Text="text here" /> <Border Grid.Column="1" Width="10" Height="10" Background="Red" /></Grid></WrapPanel>
dex3703
Wow that looks terrible. Anyway, There's a wrappanel around a grid, with * and a fixed column. It slides fluidly as the text changes. Fooling with it more I found you could have auto sized columns so long as a middle text column was * sized. The real layout has 3 different textboxes and multiple icons that are bound, so that's enough to work.Thanks for the help!!!!!!
dex3703
A: 

Someone internally suggested this answer, which works:

    <WrapPanel HorizontalAlignment="Left" VerticalAlignment="Top">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="10" />
            </Grid.ColumnDefinitions>
            <AccessText TextTrimming="CharacterEllipsis" Grid.Column="0" Margin="0,0,4,0" Text="type more typingon the long hi longer than what if you keep tyingin and get to the end and that's why it changed because you were in the middle" />
            <Border Grid.Column="1" Width="10" Height="10" Background="Red" />
        </Grid>
    </WrapPanel>

The wrappanel seems to provide the necessary magic. I haven't tried Quartermeister's but will save it for future reference!

Our final layout is more complicated and looks like this (it's the header bar for an expander):

<WrapPanel Orientation="Vertical">
    <Grid x:Name="HeaderSite" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="19" />
            <ColumnDefinition Width="16" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
            <ColumnDefinition Width="Auto" /> <!-- 7/14: fix from list: wrap the whole thing in a wrappanel. Allows for one * col. -->
            <ColumnDefinition Width="19" />
        </Grid.ColumnDefinitions>
        <ToggleButton  x:Name="buttonExpanderToggleButton"
            Height="20" VerticalAlignment="Top"
                />
        <Image x:Name="imageActivityIcon" Grid.Column="1"
            Height="16" Width="16" 
            HorizontalAlignment="Left" VerticalAlignment="Top" 
            Margin="0"/>

        <AccessText x:Name="textActivityID" 
            Grid.Column="2"
            VerticalAlignment="Top" Margin="5,2,0,0" 
            TextTrimming="CharacterEllipsis"
            FontSize="12" HorizontalAlignment="Left" Text="MA77777"/>
        <AccessText x:Name="textActivityHeader" 
            Grid.Column="3"
            VerticalAlignment="Top" Margin="0,2,0,0" 
            TextTrimming="CharacterEllipsis"
            FontSize="12" HorizontalAlignment="Left" Text="Title title title title aand Title title title title a little and if you type more what happens as you keep typing "/>
        <AccessText x:Name="textActivityStatus" 
            FontWeight="Normal" 
            FontStyle="Italic" 
            Grid.Column="4"
            TextTrimming="CharacterEllipsis"
            VerticalAlignment="Top" Margin="0,2,8,0"
            FontSize="12" HorizontalAlignment="Left" Text="(On Hold)"/>
        <Image x:Name="imageLink" 
            Stretch="None" VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="5"/>
    </Grid>
</WrapPanel>

This works fine too even with the other auto sized columns. The key seems to be the wrappanel and the one * sized column. If you set them all to auto it doesn't work.

I hope this and Quartermeister's answer helps somebody, because this drove me #$%#$% crazy.

dex3703