C# XAML Universal Apps - Change StackPanel's width as TextBoxes inside grow - c#

I have a few TextBoxes inside a StackPanel like this:
...
<StackPanel Orientation="Horizontal">
<TextBox Text="1"></TextBox>
<TextBox Text="1"></TextBox>
<TextBox Text="1"></TextBox>
</StackPanel>
...
I would like the StackPanel to grow as the TextBoxes are typed into, but instead, the TextBoxes wrap as more text is added.
How can I make the StackPanel to grow as the TextBoxes are typed into?
Thanks in advance!

When I try your solution it works for me.
But you could try to add the property TextWrapping="NoWrap" to each TextBox or create a Style.
Or you could use instead of a StackPanel a Grid which does also work
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefiniton Width="Auto" />
<ColumnDefiniton Width="Auto" />
<ColumnDefiniton Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="1" />
<TextBox Grid.Column="1" Text="1" />
<TextBox Grid.Column="2" Text="1" />
</Grid>

Related

How to apply a Grid layout to nested child elements?

I've been scratching my head over this one for a few days now. I'm trying to create a UserControl(s) that will allow me to simplify the process of creating I/O forms. In many forms I need something with a structure such as this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto">
<ColumnDefinition Width="*">
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition>
<RowDefinition>
<RowDefinition>
...
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="..."/>
<TextBox Grid.Column="1" Grid.Row="0" Text="..."/>
<TextBlock Grid.Column="0" Grid.Row="1" Text="..."/>
<TextBox Grid.Column="1" Grid.Row="1" Text="..."/>
<TextBlock Grid.Column="0" Grid.Row="2" Text="..."/>
<TextBox Grid.Column="1" Grid.Row="2" Text="..."/>
...
<Grid>
What I'd like to write is something like this:
<mycontrols:ContainerControl>
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}">
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}">
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}">
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}">
</mycontrols:ContainerControl>
The RowControl's XAML would simply be a TextBlock and a TextBox style to my liking:
<TextBlock Text="{Binding Label}"/>
<TextBlock Text="{Binding Text}"/>
As I understand there are a few issues with this:
1.- In order that an element is affected by the grid layout, it has to be an immediate child of that Grid.
2.- The number of rows is arbitrary. In a Grid you need to specify each row definition.
If I could somehow have the Grid's layout affect not only immediate children but nested ones, I think I could do this. I'm also willing to solve this with a different approach if you can think of one.
The expected finally behavior is a mixture of a StackPanel and a Grid, which is:
~ An arbitrary amount of elements can be added without defining rows (just stack them).
~ The container is divided into two columns for, first takes the size of the biggest element contained (auto), and the second takes the rest of the width available (*).
All help is welcome! Thanks in advance :)
You might be able to leverage ColumnDefinition.SharedSizeGroup and the Grid.IsSharedSizeScope attached property. Try something like this:
<UserControl x:Class="CSharpTest.RowControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="RowLabel"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Label}"/>
<TextBlock Text="{Binding Text}" Grid.Column="1"/>
</Grid>
</UserControl>
And then to use it:
<mycontrols:ContainerControl Grid.IsSharedSizeScope="True">
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}"/>
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}"/>
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}"/>
<mycontrols:RowControl Label="Some label" Text="{Binding SomeProperty}"/>
</mycontrols:ContainerControl>
mycontrols:ContainerControl could be any type of container (e.g. StackPanel, UniformGrid, etc).
In the above, the first column of each RowControl's Grid will be uniform (they will all grow to accomidate the largest Label). Depending on what's desired, you might also need to set SharedSizeGroup on the second column (to a different value, something like "RowText").

user interface in .net 4.5 and windows presentation foundation

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

Automatically size TextBlock length to length of characters (in a Grid)

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"/>

How to Add dynamic control instead of static control?

I have a collection with fields cityname, statename and countryname and I bind that collection to my wpf form. I want to display the cityname in a Textbox, the statename in a combobox and the countryname in a combobox. All the textboxes and comboboxes should come dynamically. How can I do this job?
Any one suggest me how to design this form dynamically in wpf using MVVM I am trying to do this code but not get result properly. Either I get everything as textbox or combobox, but what i need is textbox and combobox as specified.
<Border Margin="3.5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="125" />
<ColumnDefinition Width="*" MinWidth="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="tbFieldTag" Cursor="Hand" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" Margin="10,0,0,0" Text="{Binding Path=CardField.FieldTag}" />
<TextBox Margin="10,0,0,0" x:Name="txtFieldData" Grid.Column="1" MaxLength="{Binding Path=CardField.MaximumLength}" Text="{Binding Path=CardField.FieldData, Mode=TwoWay}" />
<!--<ComboBox Margin="10,0,0,0" x:Name="comboFieldData" Grid.Column="1" Text="{Binding Path=CardField.FieldTag}"/>-->
</Grid>
</Border>
The key to your problem are DataTemplates. These allow you to bind your view to a collection of custom objects.
You should have a ViewModel that is exposing an ObservableCollection<TLocation> where TLocation is a class that is exposing public properties Cityname, Statename and Countryname.
In your View you need to show a ContentControl, say a ListBox, having it's ItemSource property bound to the ObservableCollection.
Then you set the DataTemplate for the Listbox to something like:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=CityName}" />
<ComboBox Text="{Binding Path=StateName}" />
<ComboBox Text="{Binding Path=CountryName}" />
</StackPanel>
</DataTemplate>
Another approach is to use a DataGrid. See this article

Using TextWraping within a TextBox, inside a Grid for use within a ListBox in WP7

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.

Categories