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.
Related
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.
So I have a rather interesting question. I have a viewbox that has a few elements in it (a custom user control for an image, a canvas, a label, and a textbox). What I want is to try and have all elements scale with the viewbox, but I want the label and the textbox to have a "Max Size." I have tried using a max width and height on these controls but they seem to ignore it. If someone could take a look at my code below an slap me for what I am doing wrong that would be appreciated.
<Viewbox Name="myViewBox" Stretch="Uniform">
<!--Grid used to track mouse movements in this element for other reasons -->
<Grid Name="grdViewboxGrid" MouseMove="trackMouse">
<Canvas Name="cvsViewboxCanvas" MinWidth="270" MinHeight="270"
VerticalAlignment="Top" HorizontalAlignment="Center"
Panel.ZIndex="1" Background="Black"
MouseUp="Canvas_MouseUp"
MouseMove="Canvas_MouseMove">
<Grid>
<!--Would rather not post here for Intellectual Property reasons-->
<!-- Extension of the image control -->
<CustomImageUserControl />
<Grid>
<Grid Width="{Binding LabelWidthPercentage}"
MaxWidth="50"
Height="{Binding LabelHeightPercentage"
MaxHeight="26"
SnapsToDevicePixels="True" VerticalAlignment="Top"
HorizontalAlignment="Left" Margin="5" IsHitTestVisible="False">
<Label Name="lblViewboxLabel" HorizontalAlignment="Left"
Padding="5,5,5,0" Margin="0,5,0,0"
Style="{x:Null}"
Content="{Binding lblContent}" />
</Grid>
<Grid>
<Grid Width="{Binding TextBoxWidthPercentage}"
MaxWidth="156"
Height="{Binding TextBoxHeightPercentage}"
MaxHeight="45"
SnapsToDevicePixels="True" Vertical="Top"
HorizontalAlignment="Right" Margin="5" IsHitTestVisible="False">
<Border Style="{DynamicResource CustomBorder}" />
<Grid>
<Textbox Name="txtViewboxTextBox" Text="{Binding txtViewbox}" />
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</Canvas>
</Grid>
</Viewbox>
If I am not including something that is needed please let me know and I will update my question. Any help would be greatly appreciated this is now day 4 on this issue sadly :-(
I am not sure why you need so many overlapping Grids, but I hope that I can answer your question nevertheless:
In order to have the label left of the text box and to assign a maximum width to each of these two controls, use a Grid with two columns and set the MaxWidth property for each column. Then, assign the label to the left column (the one with index 0) and assign the text box to the right column (index 1). The corresponding code fragment looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="30"/>
<ColumnDefinition MaxWidth="156" MinWidth="30"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" x:Name="lblViewboxLabel" HorizontalAlignment="Left" Foreground="Yellow"
Padding="5,5,5,0" Margin="0,5,0,0"
Style="{x:Null}"
Content="{Binding lblContent}" />
<TextBox Grid.Column="1" x:Name="txtViewboxTextBox" Text="{Binding txtViewbox}" Background="Orange"/>
</Grid>
I also have assigned a MinWidth to the right column; this is necessary to make sure that the text box does not completely disappear if it contains no text.
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
I have a Grid that I populate with a TextBlock and another Grid, which is initially hidden. Since I have the TextBlock to respond to click events, I only want the method to be called when the user clicks on the text itself, not anywhere in the Grid. This is what my code looks like right now:
<Grid x:Name="LayoutRoot" Height="25">
<TextBlock x:Name="NewLabelButton" Text="Add New" Width="Auto" Foreground="Blue" TextDecorations="Underline" MouseLeftButtonUp="AddNew_OnClick" VerticalAlignment="Center"/>
<Grid x:Name="NewLabelPanel" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="NameBox" TextChanged="NameBox_OnTextChanged" KeyDown="NameBox_OnKeyDown" Grid.Column="0"/>
<Button x:Name="OKButton" Content="OK" Click="OKButton_OnClick" IsEnabled="False" Margin="2,0,0,0" Grid.Column="1"/>
<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_OnClick" Margin="2,0,0,0" Grid.Column="2"/>
</Grid>
</Grid>
Which results in the TextBlock spanning the whole width of the Grid, making it clickable from essentially anywhere in the Grid. What I want is for it to only be as wide as it needs to be to display the text (which could vary, so I can't use a static width).
Using a StackPanel instead of a Grid resolves the TextBlock width issue, but then the child Grid doesn't expand to fill the entire StackPanel, which it needs to.
Encapsulating the TextBlock in a StackPanel works, but I'm wondering if there is a better (and more efficient) way of doing it.
<Grid x:Name="LayoutRoot" Height="25">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="NewLabelButton" Text="Add New" Foreground="Blue" TextDecorations="Underline" MouseLeftButtonUp="AddNew_OnClick" VerticalAlignment="Center"/>
</StackPanel>
<Grid x:Name="NewLabelPanel" Visibility="Collapsed">
So my question is this: Is there a better way to do this than with my little StackPanel hack, or is that the only way? Thanks!
Try setting the HorizontalAlignment of the TextBlock to the left of the grid.
<TextBlock x:Name="NewLabelButton" HorizontalAlignment="Left" Text="Add New" Width="Auto" Foreground="Blue" TextDecorations="Underline" MouseLeftButtonUp="AddNew_OnClick" VerticalAlignment="Center"/>
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.