How to refer MaxWidth="??" of TextBlock to Owner ActualWidth? - wpf

How to refer MaxWidth="??" of TextBlock to stpMessage ActualWidth?
<StackPanel Name="stpMessage" Orientation="Horizontal" Margin="0,5,0,0">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Margin="0,0,0,0" Foreground="Blue" TextWrapping="Wrap">#ToUserName</TextBlock>
<StackPanel Grid.Column="1">
<TextBlock Margin="5,0,0,0" Text="{Binding Path=Text}" MinHeight="20" MinWidth="200" HorizontalAlignment="Stretch" MaxWidth="1000"
VerticalAlignment="Stretch" TextWrapping="WrapWithOverflow">START skf skdjf skdj hfskdjf ksdjhf ksjdhf ksjhf kjsf kjshf kjshkjfhsdf kjsfdkj hskdfj hskdjf hskdjf skjhfksjfks END</TextBlock>
</StackPanel>
</Grid>
</StackPanel>

The problem with this is that StackPanels do not limit the size of their children, so will grow as much as their children need
Change your StackPanel to a control that limits the size of it's children, like a Grid (or wrap it in another control) and then use an ElementName binding to bind to the ActualWidth property of that control
<Grid Name="stpMessage" ... />
...
<TextBlock MaxWidth="{Binding ElementName=stpMessage, Path=ActualWidth}" ... />
...
</Grid>

Related

WPF ListBox Header And Data Alignment

I am trying to align data with the headers in a WPF application. The headers a line up and spaced nicely. However, I cannot get the data items underneath to line up with the headers. Any suggestions?
I have been poking around a bit, but have not found a solution to my problem. I do have to stick with list box as it is part of the requirements. Also, I am new to WPF.
Here is what the output is:
And here is the xaml that I am using:
<Grid Grid.Row="2">
<ListBox ItemsSource="{Binding MyData}">
<ListBox.Template>
<ControlTemplate>
<StackPanel>
<Grid Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" x:Name="ToteNumber"></ColumnDefinition>
<ColumnDefinition Width="*" x:Name="Desription"></ColumnDefinition>
<ColumnDefinition Width="*" x:Name="Time"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Tote Number" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="Description" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="Time" HorizontalAlignment="Center"/>
</Grid>
<ItemsPresenter></ItemsPresenter>
</StackPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="1" BorderBrush="Black">
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Property1}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="1" Text="{Binding Property2}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="2" Text="{Binding Property3}" HorizontalAlignment="Stretch"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You need to set Grid.IsSharedSizeScope="True" on a parent panel and you need to identify the SharedSizeGroup on each column so it knows which column in your listbox template grid corresponds to which one in your itemtemplate.
Note that I think * width is treated as Auto when you apply Sharedsizegroup.
I use width auto and minwidth instead when I've done something similar.
You may find you need to bind width of each column to some parent measuring grid or calculate minwidth using a converter based on ViewportWidth of the scrollviewer in your listbox.
<Grid Grid.Row="2" Grid.IsSharedSizeScope="True">
<ListBox ItemsSource="{Binding MyData}">
<ListBox.Template>
<ControlTemplate>
<StackPanel>
<Grid Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="A" x:Name="ToteNumber"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="B" x:Name="Desription"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="C" x:Name="Time"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Tote Number" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="Description" HorizontalAlignment="Center"/>
<TextBlock Grid.Column="2" Text="Time" HorizontalAlignment="Center"/>
</Grid>
<ItemsPresenter></ItemsPresenter>
</StackPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Border BorderThickness="1" BorderBrush="Black">
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="A"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="B"></ColumnDefinition>
<ColumnDefinition Width="*" SharedSizeGroup="C"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Property1}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="1" Text="{Binding Property2}" HorizontalAlignment="Stretch"/>
<TextBlock Grid.Column="2" Text="{Binding Property3}" HorizontalAlignment="Stretch"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As I mentioned, I use a similar technique in some of my own markup. For that I put the headers grid and then the listbox with an itemtemplate in a stackpanel.
<StackPanel>
<Grid>
Headers
<ListBox>
ItemTemplate
</StackPanel>
Sounds like that doesn't suit whatever is driving your requirements though.

How to center UserControl in a TabControl

My MainWindow is built with TabContol containing in each tab UserControl in xaml files. Opening specific UserControl is not a problem, but aligning it is. I was able to horizontally center content of tab but struggle to vertically do this same. I found out that the root problem is that UserControl don't take the whole free space (height) in the Tab. I tried to make main grid VerticalAlignment="Stretch" and "Center" but that didn't help. I could use margin with specific number or define row fixed hight but that will not work on every resolution and I don't want to write method in code behind but use the power of xaml. How can I force UserControl to take whole height in Tab and then vertically center it (it's important to do it for specific UserControl because others should have default position)?
ps. I'm using MetroWindow from MahApps.Metro.
MainWindow main Grid:
<Grid>
<StackPanel>
<TabControl ItemsSource="{Binding Tabs}"
SelectedIndex="0">
<TabControl.Resources>
<Style TargetType="{x:Type TabPanel}">
<Setter Property="HorizontalAlignment"
Value="Center" />
</Style>
<DataTemplate DataType="{x:Type VMod:LoginViewModel}">
<Pages:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:AdminViewModel}">
<Pages:AdminView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:ProductsViewModel}">
<Pages:ProductsView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:DistributionViewModel}">
<Pages:DistributionView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:SummaryViewModel}">
<Pages:SummaryView />
</DataTemplate>
<DataTemplate DataType="{x:Type VMod:SettingsViewModel}">
<Pages:SettingsView />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type inter:ITab}">
<TextBlock>
<Run Text="{Binding TabName}" />
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</StackPanel>
</Grid>
UserControl main Grid:
<Grid Background="LightBlue"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Height="300"
Width="300"
Grid.Row="2"
BorderBrush="LightGray"
BorderThickness="1">
<StackPanel HorizontalAlignment="Center">
<iconPacks:PackIconRPGAwesome Kind="Honeycomb"
HorizontalAlignment="Center"
Width="60"
Height="60"
Margin="0, 0, 0, 0"/>
<TextBlock HorizontalAlignment="Center"
Text="DistributionTool"
FontSize="20"
FontWeight="Bold"
Margin="5" />
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Margin="5"
TextAlignment="Left"
FontSize="15"/>
<iconPacks:PackIconMaterial Grid.Column="1"
Kind="AccountTie"
Width="20"
Height="20"
VerticalAlignment="Center"/>
</Grid>
<Grid Width="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<PasswordBox Grid.Column="0"
Margin="5"
HorizontalContentAlignment="Left"
FontSize="15"
Style="{StaticResource Win8MetroPasswordBox}" />
<iconPacks:PackIconMaterial Grid.Column="1"
Kind="Key"
Width="20"
Height="20"
VerticalAlignment="Center" />
</Grid>
<Button Content="LOGIN"
Width="80"
metro:ControlsHelper.ContentCharacterCasing="Normal"
Margin="5"
Style="{StaticResource AccentedSquareButtonStyle}" />
</StackPanel>
</Border>
</Grid>
From what I gather, what you could try would be:
Remove the StackPanel in your MainWindow Grid. Unless you intend to have more than 1 child inside the stack panel (Other than your TabControl), it is useless.
Add VerticalAlignement="Stretch" to your TabControl. This will allow it to take up all the space it can vertically.
Then you should be pretty much set to go.
The reason why you shouldn't use a StackPanel unless you intend to stack items inside, as in
<StackPanel>
<Child1/>
<Child2/>
</StackPanel>
is that the StackPanel.Orientation property affects how things will appear inside, including the Alignement of each child.
So Orientation="Vertical" (the default), affects the VerticalAlignement of its children. Same idea with Horizontal.

Why doesn't a textbox stretch inside stackpanel WPF?

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="49*" />
<ColumnDefinition Width="25*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Margin="30" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,5,0" Text="Username:" />
<TextBox HorizontalAlignment="Stretch"/>
</StackPanel>
</StackPanel>
--Result image--
Im trying to make it so that the textbox will fill the rest of the space inside the current StackPanel.
however the "Stretch" propety doesn't seem to work - why is that?
Is there a different way do it or what am I doing wrong?
A StackPanel always tries to achieve the minimum possible height/width, depending on orientation; therefore, Stretch has no effect. You might want to use a DockPanel instead, which allows children to stretch:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="49*" />
<ColumnDefinition Width="25*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1"
Margin="30"
VerticalAlignment="Center">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Margin="0,0,5,0"
Text="Username:" />
<TextBox HorizontalAlignment="Stretch"/>
</DockPanel>
</StackPanel>
</Grid>

WPF Statusbar, stretch textblock to take as much space as possible

I created my own simple statusbarcontrol with 3 TextBlocks. Now I would like that the first Textblock takes as much space as it has available. That I don't seem to get done.. Now it only takes the space needed to display the text.
XAML:
<StatusBar Background="{StaticResource GradientBrush}">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem HorizontalAlignment="Left"
HorizontalContentAlignment="Right">
<Border BorderThickness="1"
BorderBrush="Black"
Padding="5 0 5 0"
Background="White">
<TextBlock Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding TextColorMessage}"
Background="White"
/>
</Border>
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2"
HorizontalAlignment="Right">
<TextBlock Text="{Binding Path=DatabaseName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StatusBarItem>
<Separator Grid.Column="3" />
<StatusBarItem Grid.Column="4"
HorizontalAlignment="Right">
<TextBlock Text="{Binding Path=ComputerName}" />
</StatusBarItem>
Well this is pretty straight forward:
you had set the StatusBarItem HorizontalAlignment="Left" when it should be "strech", same for the HorizontalContentAlignment.
Also would suggest setting margin=0 on the border.
this is what i did so it will work for me:
<StatusBarItem HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<Border BorderThickness="1"
BorderBrush="Black"
Margin="0"
Padding="5 0 5 0"
Background="White">
<TextBlock Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding TextColorMessage}"
Background="White"/>
</Border>
</StatusBarItem>
if this is helpful please mark as answer
Try setting the StatusBarItem's HorizontalAlignment and HorizontalContentAlignment to Stretch.
Set the StatusBarItem's HorizontalContentAlignment to Stretch and the TextBlock's TextAlignment property to Right. (This second setting is only needed for the first StatusBarItem as it seems that you try to align the text to the right in it.)
StatusBar has only one HorizontalAlignment=Right item to effect, so you can get only the last item in wanted place. You can set statusBar's FlowDirection="RightToLeft" and add item in reversed order. Details: right placed items needn't StatusBarItem surrounded, but the left one need to be streched. Following code:
<StatusBar VerticalAlignment="Bottom" FlowDirection="RightToLeft"><!--flow right to left cause items right aligned-->
<!--make item's flow back left to right, avoid display disorder-->
<TextBlock x:Name="textBlock_status_R1" Text="111.147.168.20" Grid.Column="2" Margin="10,0" FlowDirection="LeftToRight"/>
<Separator/>
<TextBlock x:Name="textBlock_status_R2" Text="Working" Margin="10,0" FlowDirection="LeftToRight"/>
<Separator/>
<!--To fill rest space,need StatusBarItem packing and default HorizontalAlignment="Stretch"-->
<StatusBarItem FlowDirection="LeftToRight">
<TextBlock x:Name="textBlock_status_L1" Text="Information here."/>
</StatusBarItem>
</StatusBar>

Horizontal scroll bar prevents text box wrapping

I am trying to make TextBox to wrap text and grow with the Window. That works if I don't set ScrollViewer's HorizontalScrollBarVisibility property. But if I do, TextBox will grow infinitely. The problem is solved by setting MaxWidth property to the TextBox, but in that case TextBox does not grow beyond the MaxWidth value. My idea was then to bind MaxWidth to ColumnDefinition's ActualWidth, but that also doesn't work because ColumnDefinition's ActualWidth property is not a DependencyProperty. Here is my code:
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" Margin="5" />
<TextBox MinWidth="200" Grid.Row="0" Grid.Column="1" TextWrapping="Wrap" AcceptsReturn="True" Margin="5"/>
</Grid>
</ScrollViewer>
Any ideas will be appreciated.
Try this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Name:" Margin="5" />
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Column="1">
<TextBox MinWidth="200" TextWrapping="Wrap" AcceptsReturn="True" Margin="5" MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ScrollViewer}}}" />
</ScrollViewer>
</Grid>

Resources