How to clip textblock inside proportional grid? - c#

In a UserControl that's inside a ListBox, I've got a TextBlock with proportional width (Width="*") inside a Grid that I want to take the remaining width of the grid, but whenever I resize the ListBox to a size that would clip that TextBlock's content I get a scroll bar. How can I clip the TextBlock width so that I don't get an horizontal scroll bar? Ideally clipping it with ellipsis.
EDIT: Forgot to mention the ListBox.

The listbox is scrolling because it's default behavior is to have HorizontalScrollBarVisibility to Auto.
Try setting this property to disabled:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
As for clipping to an ellipse, this is more complex. You can clip to an ellipsis quite easily using the Clip property:
<TextBlock Text="Some very long thing that I'm putting in here to clip" Background="Blue">
<TextBlock.Clip>
<EllipseGeometry Center="100,8" RadiusX="100" RadiusY="8" />
</TextBlock.Clip>
</TextBlock>
However, to keep the Center, RadiusX and RadiusY in order you'll have to bind it to the height and width of the text box (perhaps using a converter to half these values).

Related

Why StackPanel does not stretch its children vertically?

(new to WPF) I am looking over the WPF example:
<Window x:Class="Attempt_XAML.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Label HorizontalAlignment="Center">A Button Stack</Label>
<Button HorizontalAlignment="Left">Button 1</Button>
<Button HorizontalAlignment="Right">Button 2</Button>
<Button Background="#FFA29494">Button 3</Button>
<Button>Button 4</Button>
</StackPanel>
</Window>
Remark in MS notes that:
The default value is stretch for both HorizontalAlignment and
VerticalAlignment of content that is contained in a StackPanel.
However, result looks different from what I am expecting. Button and Label are not stretched out vertically, but only horizontally(i.e they don't fill the entire space of Window in both directions) Why ?
Button and Label are not stretched out vertically, but only horizontally(i.e they don't fill the entire space of Window in both directions) Why ?
To understand the reason, you really need at least a basic understanding of Panels. Any Panel such as a StackPanel uses a measure-arrange cycle to decide on a layout for its child elements:
in the "measure" cycle, it assigns a size to each child
in the "arrange" cycle, it positions each child in its view
The key feature of a StackPanel is that it has infinite space -- infinite horizontal space if its orientation is Horizontal, and infinite vertical space if Vertical. In other words, it does not actually pay attention to the size available to it (in the direction of its orientation), but claims an infinite space. So therefore, coming back to your example, even though the VerticalAlignment of the children may be Stretch, they cannot actually be stretched out to an infinite size.
If you need a panel that stretches out its children to fill the available space, then Grid is a good example (by default the Grid will assign an equal share of the total height to each child -- or you can use the star sizing to adjust the proportions). You could also consider creating your own custom Panel, if you need a specialized layout behavior.
Edit
To clarify "infinite space": what I mean is that the StackPanel tells its children that there is infinite space available. What do you do if you are a Button, Label, etc, and there is infinite space available? You probably just take up the minimum space you need, even if your VerticalAlignment is "Stretch", right? That's what happens. Contrast to a Grid, which tells the child controls that they have x (finite) amount of space -- in that case, a Button, Label, etc, will fill up all that space (if their VerticalAlignment is "Stretch").
To illustrate the above, take this custom control as an example:
public class TestControl : ContentControl
{
public string Description { get; set; }
protected override Size MeasureOverride(Size availableSize)
{
System.Diagnostics.Debug.WriteLine("Size available for '" + Description + "': " + availableSize.Height);
return base.MeasureOverride(availableSize);
}
}
This doesn't actually do anything, just reports how much space has been allocated to it. Now, place the test control in a Grid and a StackPanel, and compare:
<Grid Height="50">
<Grid.RowDefinition />
<Grid.RowDefinition />
<local:TestControl Description="in Grid" />
<StackPanel Grid.Row="1" Height="10">
<local:TestControl Description="in StackPanel" />
</StackPanel>
</Grid>
You'll see that the Grid assigns its CustomPanel (the first one above) a height of 25 (half its height). The StackPanel, though, assigns its CustomPanel a height of Infinity.
Although default value is stretch for both HorizontalAlignment and VerticalAlignment of Content that is contained in a StackPanel. But in which direction to stretch is controlled by Orientation Property.
If Orientation is set to Vertical then all the items of the stack with no defined width value are stretched only.

Canvas improperly overlaying a TextBlock component inside a DockPanel

In the image here, each block with a number in it represents a laser. These blocks are laid out on a canvas inside a DockPanel. Also inside the DockPanel docked to the top is the red TextBlock that you can see is hiding behind the laser map canvas. Why is this happening? The TextBlock is docked to the top of the DockPanel and canvas has no dock setting, therefore it should fill the rest of space. Also of note: I had to put the DockPanel inside a ViewBox in order for the whole center screen space to scale properly on window resizes. Then I had to put that ViewBox inside a ScrollViewer to allow scroll bars to appear when needed.
Here is the XAML Code for the center screen (Note: Child of the Window is a DockPanel. Menu is docked to the top, left-hand button panel is docked to the left, right-hand button panel is docked to the right, the status bar is docked to the bottom and everything you see in the center screen is defined by the following XAML code)
<ScrollViewer
Name="centerScreenScrollViewer"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="{Binding IsScrollbarsVisible, Converter={StaticResource BoolToScrollbarVisConverter}, FallbackValue=Hidden}">
<Viewbox>
<DockPanel
LastChildFill="True">
<TextBlock
DockPanel.Dock="Top"
Name="tbkFullVisual"
Style="{StaticResource tbkStyleBlue}"
Foreground="Red"
IsEnabled="{Binding FullVisual}"
HorizontalAlignment="Center"
VerticalAlignment="Top"
FontSize="24">
*** This Print Requires Full Visual Inspection! ***
</TextBlock>
<Canvas x:Name="mapCanvas">
<ContentPresenter Content="{Binding MapCanvas}"/>
</Canvas>
</DockPanel>
</Viewbox>
</ScrollViewer>
Any help in solving this issue will be greatly appreciated.
Regards,
Kyle
This has to do with the way that a ViewBox works, in particular with the Canvas element. The ViewBox is used to resize child elements, as I'm sure you're aware. There are 2 issues with the Canvas element:
The default Height and Width are 0, which means that the TextBlock will get all the space.
The Canvas element lets you draw outside of its own boundaries, so even if your canvas is tiny or not even visible, you would be allowed to render your grid of numbers.
The quickest solution is to set VerticalAlignment on the ViewBox:
<Viewbox VerticalAlignment="Top">
...
</Viewbox>
You could set a Height on the Canvas, but I think this is less ideal because you don't want to change this dynamically with window resize.

C# XAML ScrollViewer to work without MaxHeight

I have a grid that further down have a StackPanel. I have defined the row's height for the last to be "*", and in this very last row, is where the StackPanel and all the control would inhabit.
So I have the bellow code in XAML for my StackPanel
<StackPanel Grid.Row="1" MaxHeight="333">
<StackPanel MaxHeight="333">
<ScrollViewer MaxHeight="333">
<TextBlock x:Name="lblRouteDetail" FontSize="35" TextWrapping="Wrap"/>
</ScrollViewer>
</StackPanel>
</StackPanel>
Well, it worked, only that I have to constraint that the MaxHeight is 333, without that, it won't work; the ScrollViewer won't work, the content in the TextBlock wouldn't be scrollable.
Could you state where is my problem, and how to fix this things up?
A StackPanel, unless set to a specific height (or width if its orientation is set to Horizontal), does not constrain the height of its children, but is sized according to them. If you want to scroll your controls, you could either keep the MaxHeight property or use a different panel for holding them, such as a Grid or a DockPanel.

Canvas overrides the TextAlignment value of TextBlock inside it

I am trying to configure the TextAlignment of a TextBlock that is a child of a Canvas. I realized that in a grid the TextAlignment works, but when in a Canvas you can't configure it as Center.
I really hope someone could help and shed some light on this topic.
A relatively easy solution is to wrap your TextBlock in a StackPanel with a width, and set the TextBlock's HorizontalAlignment to Center. This will center the text in the StackPanel.
The Width is the important part. Without the Width, the TextBlock wouldn't know how much room it has, and therefore how to center itself.
The Canvas will always give it's child elements their "desired size". So if your TextBlock needs to be 100 pixels wide to display it's text, then the Canvas will give it exactly 100 pixels. A Grid on the other hand, can give the TextBlock more or less space depending on what column/row the TextBlock is in.
For single lines of text (i.e. no new lines), the only time TextAlignment comes into play is when the TextBlock is given more (or less if TextWrapping is enabled) space than it needs.
For multiple lines of text (or in the case of text wrapping a single line), then the TextAlignment will align it's text withing the bounds of the TextBlock.
Since a Canvas will never force a TextBlock to wrap, the only time TextAlignment comes into play there is with multiple lines of text.
<Canvas Width="300" Height="50">
<TextBlock Canvas.Top="0" TextAlignment="Center">
This will not center
</TextBlock>
<TextBlock Canvas.Top="25" TextAlignment="Center">
This will center the shorter<LineBreak />lines of text
</TextBlock>
</Canvas>

How to have a vertical scrollbar for a WPF TreeView, but not the horizontal scrollbar?

I have a TreeView (the only control) inside a Grid, and I only want to see the vertical scrollbar when the height isn't enough.
To not have the horizontal scrollbar, I have to account for its width to the width of the TreeView, right? But when I only specify the width to stretch the TreeView's width to the width of the Window, no scrollbar appears.
Is there a way to solve this?
Alternatively if I can make it so that I don't have to specify the width and height of the TreeView and it resizes its width when the height isn't enough, to fit the vertical scrollbar, that would be the best.
I use these attributes on my TreeView's ScrollViewer:
<TreeView ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
As long as the width of your TreeView's content stretches to just fit the width of your TreeView, you should be fine.

Categories

Resources