I am still trying to get my head around wpf ui creation. I have created a user control which has a expander, dockpanel and two comboboxes in the dockpanel with equal width hardcoded in xaml. It looks good during the design time and in runtime as long as the expander widths is unchanged. When the expander header is changed to a longer text the dockpanel streches and the two comboxes remain the same size. They are docked to the right hence there is a lot of gap between two comboxes.
My question, is there a way to equally space the two comboboxes in the dockpanel.
Code:
<DockPanel Height="Auto"
DockPanel.Dock="Top"
HorizontalAlignment="Stretch" Name="lhsInput"
VerticalAlignment="Stretch" Width="Auto"
LastChildFill="False">
<ComboBox Height="23" Name="cboLHSItem"
Width="84" FontWeight="Normal"
Margin="1,0,0,0" Foreground="Black" FontFamily="Tahoma" />
<ComboBox Height="23" DockPanel.Dock="Right"
Name="cboLHSValues" Width="79" FontWeight="Normal"
IsEditable="False" Margin="0,0,1,0" FontFamily="Tahoma"
Foreground="Black" />
</DockPanel>
You could use Grid instead of DockPanel, Sample code below:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ComboBox Height="23" Name="cboLHSItem"
MinWidth="79"
Grid.Column="0"
FontWeight="Normal"
Foreground="Black" FontFamily="Tahoma" />
<ComboBox Height="23" MinWidth="79"
Grid.Column="1"
Name="cboLHSValues" FontWeight="Normal"
IsEditable="False" FontFamily="Tahoma"
Foreground="Black" />
</Grid>
DockPanel may be providing the required Width for its Child elements. However, with Grid and its RowDefinitions and ColumnDefinitions you can specify whether you want "Auto" Width/Height or you want to use whatever is available for Width/Height. The above code specifies to use Whatever width available for the Child element by setting Width to * in ColumnDefinition.
UPDATE
To Understand how different Panels of WPF work, refer to MSDN page: Panels Overview
Related
I have a TextBox, which I want to be multiline and automatically sized to parent:
<TextBox Grid.Row="0" Grid.Column="0"
AcceptsReturn="True"
HorizontalAlignment="Stretch"
IsEnabled="{Binding CanModify}"
Margin="0"
TextWrapping="Wrap"
Text="{Binding Comment, UpdateSourceTrigger=PropertyChanged}"
VerticalScrollBarVisibility="Auto"
VerticalAlignment="Stretch"
/>
Most suggestions to make the TextBlock automatically switch to new line are about adding TextWrapping="Wrap" to it's properties, to prevent it from stretching it's usually AcceptsReturn="True", VerticalScrollBarVisibility="Auto" or manually set width. As you see, the only thing that I haven't yet tried is width, but in my case TextBox should fit to container, which width is unknown (also depends on it's parent). Having properties set as in listing doesn't help: caret never moves to new line and stretches the TextBox and the whole window as well.
What can I do to prevent this TextBox from stretching and to move text to new line automatically?
EDIT: Container is a TabControl. Containing tab:
<TabItem Header="{some binding}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="TabHeight" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TabWidth" />
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0" Grid.Column="0"
AcceptsReturn="True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
IsEnabled="{Binding CanModify}"
Margin="0"
Style="{some style}"
TextWrapping="Wrap"
Text="{Binding Comment, UpdateSourceTrigger=PropertyChanged}"
VerticalScrollBarVisibility="Auto"
/>
</Grid>
</TabItem>
This TabControl lies in a simple Grid without any specific styles of constraints. Alas, I can't share the whole code of styles, applied to TabControl, but I'd highly appreciate any ideas to try.
SharedSizeGroups you see are intended to stretch the whole TabControl to the widest tab, preventing it from resizing on tab switches and shared only with another tab (there are two in this TabControl).
i want to auto stretching elements horizontally to grid width, so when you stretch window elements must proportionally stretched with it.
<Grid Margin="0,0,0,40" Name="TaskGrid" Visibility="Hidden">
<StackPanel Name="AmountOfSP" Visibility="Collapsed" Orientation="Horizontal" HorizontalAlignment="Stretch">
<CheckBox Name="restrRadioButton" Checked="restrCheckBox_Checked" Unchecked="restrCheckBox_Unchecked"/>
<TextBlock TextWrapping="Wrap" Text="bla-bla" />
<TextBox Name="AmountOfO" HorizontalAlignment="Stretch" MinWidth="70" Height="20" Margin="10,0,0,0"/>
</StackPanel>
</Grid>
As I've answered here you can't use a StackPanel to strech in the stacking direction, because it will always use the smallest possible size for the stacking elements (unless they have a fixed size, then it will utilize that).
Use a DockPanel or Grid instead and order the inner components appropriately to stretch to the full size.
Adding one more option along with the mentioned answer. You can also make use of UniformGrid to achieve what you want.
<Grid Margin="0,0,0,40" Name="TaskGrid">
<UniformGrid Name="AmountOfSP" Columns="3" HorizontalAlignment="Stretch">
<CheckBox x:Name="restrRadioButton"/>
<TextBlock TextWrapping="Wrap" Text="bla-bla" />
<TextBox Name="AmountOfO" HorizontalAlignment="Stretch" MinWidth="70" Height="20" Margin="10,0,0,0"/>
</UniformGrid>
</Grid>
You can replace your stackpanel with a grid similar to the one shown below;
<Grid Name="AmountOfSP" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Name="restrRadioButton" Grid.Column="0" Checked="restrCheckBox_Checked" Unchecked="restrCheckBox_Unchecked"/>
<TextBlock Grid.Column="1" TextWrapping="Wrap" Text="bla-bla" />
<TextBox Grid.Column="2" Name="AmountOfO" HorizontalAlignment="Stretch" MinWidth="70" Height="20" Margin="10,0,0,0"/>
<Grid>
You can play around with widths of your different controls by changing the columnDefinition widths e.g.
<ColumnDefinition Width="Auto"/>
As it stands all three of your columns will have the same width and will expand to fill the control it occupies.
You cannot use as stack panel in this way because it literally just gets it's width/height by "stacking" (adding) the widths/heights of the controls it contains.
You may find work-arounds using the stack panel but it is much easier just to use a different control meant to do the job you are after.
im trying to bind the width of a button and a TextBox to the width of a column they are in. Additionally i want to change the visibility of the whole grid. I set visibility to "Collapsed" and in the code behind file i change the visibility to visible
C#:
Grid1.Visibility = Visibility.Visible;
The TextBlocks in the Grid are visible, but the Textbox and the button are not, i guess the width is 0, because of the grid being invisible. Whats the best way to tell the button to update the width after changing the visibility to visible?
This is the xaml code
<Grid x:Name="Grid1" Margin="0,100,0,0" Visibility="Collapsed"> <!--HERE -->
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="Column0" Width="100"/>
<ColumnDefinition x:Name="Column1" Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="60"/>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding MaterialName, Mode=OneWay}" VerticalAlignment="Center" FontSize="40"/>
<TextBlock Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" TextWrapping="Wrap" Text="Anzahl:" FontSize="30"/>
<TextBox
Grid.Column="1"
Grid.Row="1"
x:Name="QuantityTextBox"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Height="72" TextWrapping="Wrap"
Text="{Binding Quantity, Mode=TwoWay}"
Width="{Binding ElementName=Column1, Path=ActualWidth}"/><!-- HERE -->
<Button
Grid.Column="1"
Grid.Row="2"
Width="{Binding ElementName=Column1, Path=ActualWidth}"
Content="Content1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
x:Name="ButtonName"
Click="Button_Click"/>
</Grid>
If I understand correctly, you want the TextBox and Button to Stretch to the Width of the Grid.Column they are in. If so, the HorizontalAlignment property on your TextBox and Button are causing the problem. The default HoriziontalAlignment is Stretch so you shouldn't need to define any HorizontalAlignment (or Width) and the controls will size to fit available width. Try this:
<TextBox
Grid.Column="1"
Grid.Row="1"
x:Name="QuantityTextBox"
VerticalAlignment="Center"
Height="72" TextWrapping="Wrap"
Text="{Binding Quantity, Mode=TwoWay}" ><!-- HERE -->
<Button
Grid.Column="1"
Grid.Row="2"
Content="Content1"
VerticalAlignment="Top"
x:Name="ButtonName"
Click="Button_Click"/>
It's also helpful to set ShowGridLines="True" on your Grid when dealing with layout issues.
I don't think that your problem is Visibility related (or at least just Visibility related). I just remembered that you can't directly data bind a ColumnDefinition.Width property to a Button.Width property because they are of different types. The Button.Width property is obviously of type double, but the ColumnDefinition.Width property is actually of type GridLength.
Instead, you would have to data bind between the two using some sort of IValueConverter. I just found one that you could use from the answer to the How do I databind a ColumnDefinition's Width or RowDefinition's Height? question that you could use.
Of course, once you have done that, you might still have problems because of the Visibility issue, so we might have to return to that later.
I cant figure out what I am doing wrong I have a grid with 2 columns and 3 rows. In the left column I have a textblock and textbox and a listbox which is all good.
The right column gets a little more complicated where I have a tabcontrol to start. Then my TabItem and inside that I have my Main Grid and then inside that I have 2 grids. Which are grdDetailsTop and then grdDetailsBottom.
grdDetailsTop has 3 columns where the left will be an image with a Border the middle should be Member Code: 'TextBox' and under that should be Family Code: 'TextBox' and then finally under that I would like to place Balance: 'TextBox'
The way I tried it was, I have grdDetailsTop Grid with 3 columns in the first column I placed a groupbox and inside that I have a stackpanel.
Second Column is where I am having trouble I placed a Stackpanel with the orientation Horizontal and grid.Column="1" but my textblocks are going into the 3rd column without me telling them too. Sorry for the bad explanation but the code is posted hopefully you can help. Also the reason for my different Panels is so I can place a border around each column of the grdDetailsTop.
Thanks
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"></ColumnDefinition>
<ColumnDefinition Width="70*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="5*"></RowDefinition>
<RowDefinition Height="100*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="Search Member" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20"></TextBlock>
<TextBlock Text="Member Details" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20"></TextBlock>
<TextBox Name="txtMEMSearch" Background="Orange" Grid.Column="0" Grid.Row="1"></TextBox>
<ListBox Name="lstSearchMembers" Grid.Row="2"
BorderBrush="Black" DisplayMemberPath="Name"
ItemsSource="{Binding ElementName=bindingToObject,
Path=Clients}" />
<TabControl Name="mainTabControl" Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5">
<TabItem Header="Member Details" Name="memDetailTab">
<Grid Name="mainTabGrid">
<Grid Name="grdDetailsTop" Height="175" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<GroupBox Header="Picture">
<StackPanel>
<Image Height="125" Width="125"></Image>
</StackPanel>
</GroupBox>
*************PROBLEM AREA******************
<StackPanel Margin="5" MaxWidth="200" Orientation="Horizontal" Grid.Column="1">
<TextBlock
VerticalAlignment="Top"
Margin="5"
Height="25">Member Code:</TextBlock>
<TextBlock
VerticalAlignment="Top"
Margin="5"
Width="75"
Height="25"></TextBlock>
<TextBlock
Margin="5"
Height="25"
Width="100">Family Code:</TextBlock>
<TextBlock
Margin="5"
Width="75"
Height="25"></TextBlock>
<TextBlock
VerticalAlignment="Bottom"
Margin="5"
Height="25"
Width="100">Balance Due:</TextBlock>
<TextBlock
Margin="5"
VerticalAlignment="Bottom"
Width="75"
Height="25"></TextBlock>
</StackPanel>
******************************************
</Grid>
<Grid Name="grdDetailsBottom">
</Grid>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Page>
You're missing the VerticalAlignment = "Top" on that TextBlock, and therefore, it is defaulting to Stretch which will center the text in the available vertical space. If you set that property, you'll see that it moves back up to be in line with the other TextBoxes in the same StackPanel.
It isn't actually moving that TextBox into the next column, rather, you've defined a fixed width of the column it is in (in this case, column 1 with a width of 200). But the contents of that column (the StackPanel are more than 200 units wide, so they push over into the next grid column. To keep all the TextBoxes in column 1, you'll either need to widen the column so they can fit, shrink the size of the TextBoxes or set the width Auto so it will automatically size itself to its contents. If you look at it, you're taking up 175 units with TextBlocks 2 and 3, leaving only 25 units for the rest of the TextBlocks in that StackPanel. There's just not enough space.
<StackPanel Margin="5" MaxWidth="200" Orientation="Horizontal" Grid.Column="1">
<TextBlock VerticalAlignment="Top" Margin="5" Height="25">Member Code:</TextBlock>
<TextBlock VerticalAlignment="Top" Margin="5" Width="75" Height="25"></TextBlock>
<TextBlock VerticalAlignment="Top" Margin="5" Height="25" Width="100">Family Code:</TextBlock>
... other text boxes ...
</StackPanel>
This will fix the vertical layout issue, but not the Horizontal layout issue. That requires changes to the grid column sizing or the size of the contents.
Per your comment below, I believe you're looking for the WrapPanel which will automatically wrap items to the next line (horizontal or vertical) when it runs out of space.
<WrapPanel Margin="5" MaxWidth="200" Orientation="Horizontal" Grid.Column="1">
<TextBlock VerticalAlignment="Top" Margin="5" Height="25">Member Code:</TextBlock>
<TextBlock VerticalAlignment="Top" Margin="5" Width="75" Height="25"></TextBlock>
<TextBlock VerticalAlignment="Top" Margin="5" Height="25" Width="100">Family Code:</TextBlock>
... other text boxes ...
</WrapPanel>
This layout certainly looks nicer. But - I don't know your specific requirements, however rather than using a WrapPanel with fixed margins and sizes, I would recommend using a Grid with ColumnDefinitions and RowDefinitions to organize items in this type of layout. The Grid offers a much greater level of flexibility and allows for items to automatically resize based on system font sizes, a user resizing your view and other factors out of your control. If you are setting fixed heights/widths, you lose that flexibility. Again, I don't know you're requirements, so perhaps this is the best solution for you, but under most circumstances, I'd highly recommend a Grid instead.
I am trying to get my data to display properly within a GridLayout, which is to be used as a DataTemplate for an Item within ListBox. Here is the code associated with what I am doing:
<Grid Name="FeedItemTemplate">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding ProfileImage}" Grid.RowSpan="2" Height="75" Width="75" VerticalAlignment="Center" Margin="1" />
<TextBlock Text="{Binding UserName}" Grid.Column="1" Foreground="#FFC8AB14" FontSize="28" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding TimeStamp}" Grid.Column="2" TextWrapping="Wrap" FontSize="18" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding Message}" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" TextWrapping="Wrap" FontSize="24" />
</Grid>
The issue is that using this layout, when TextWrapping is set to Wrap, the Item is displayed correctly, but when scrolling through the ListBox everything is really jittery, you cannot scroll in small increments, and it just jumps all over the place.
Any reason why it does this? As I said, only when TextWrapping is set to Wrap it does this. When its not used, it scrolls fine, but the text is all along one line and off the screen.
Does it keep jumping if you explicitly set the top-level Grid element's width to a fixed size?
For some reason that I do not fully understand, settings the ListBox's ItemsPanel property to a StackPanel might solve your problem:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="MyItemsPanelTemplate">
<StackPanel/>
</ItemsPanelTemplate>
</UserControl.Resources>
...
<ListBox ... ItemsPanel="{StaticResource MyItemsPanelTemplate}"/>
This is a known issue with listbox scrolling in the current ctp when you have variable height items. The workaround for now is to set a fixed height on your listbox item content. You'll probably also notice the scroll bar doesnt properly go to the bottom all the time. The workaround fixes that too.
Reference.