Set 2-Line text box - c#

Goal:
I'm trying to create a TextBox with space for exactly 2 lines.
The content will later be filled into a document which has a maximum space for two lines.
The user should be able to see that visually in the application to generate the Document:
Current Situation / Issue
The TextBox sits in a Grid with <RowDefinition Height="auto"></RowDefinition>. This leads the Textbox to occupy exactly 1 Line of space (marked in yellow):
Only when the first letter is beeing typed, the textbox expands to two lines due to MinLines="2". I do have the Idea to set a static height to the Grid.Row but to be honest, I really dislike static sizing and I feel that it is not the apropriate solution.
Additionally, eventhough MaxLines="2" the textbox will happily wrap around any number of lines.
I have set MaxLength="200" - It kind of does the Job but has nothing to do with the actual text size.
(iiiii vs WWWWW)
Current Code:
<Grid x:Name="EigenbelegGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<!-- Preset -->
<Label Content="Preset" Grid.Column="0" Grid.Row="0"></Label>
<ComboBox x:Name="TemplateSelection_DropDown" Grid.Column="1" Grid.Row="0" IsEditable="True"
<Button x:Name="SavePreset_Button" Content="Save" Grid.Column="2" Grid.Row="0"></Button>
<Button x:Name="DeletePreset_Button" Content="Delete" Grid.Column="3" Grid.Row="0"></Button>
<!-- Reasoning -->
<Label Content="Begründung" Grid.Column="0" Grid.Row="1"></Label>
<TextBox x:Name="Reasoning_TextBox" Grid.Column="1" Grid.Row="1" MinLines="2" MaxLines="2" TextWrapping="Wrap" MaxLength="200"></TextBox>
</Grid>

After being loaded to visual tree, if TextBox is blank, DesiredSize will contain the height of one line plus the height of other causes, and ExtentHeight will contain the height of one line. We can use this two to calculate the actual height we need. In your case, it will be like
<TextBox x:Name="Reasoning_TextBox" Grid.Column="1" Grid.Row="1" MaxLines="2" TextWrapping="Wrap"
Loaded="Reasoning_TextBox_Loaded"></TextBox>
private void Reasoning_TextBox_Loaded(object sender, RoutedEventArgs e)
{
TextBox t = (TextBox)sender;
t.Height = t.DesiredSize.Height + t.ExtentHeight * (t.MaxLines - 1);
}

Related

How to structure a stacked form with WPF XAML?

On my Window, I've got a GroupBox. I'd like to build out a horizontally aligned form inside of that GroupBox. By horizontally aligned, I mean a form where the label and the input reside on the same grid row or x axis. Separate form labels + inputs reside on their own row.
Since a GroupBox can only have one child content, I assume I need to either use a Grid or StackPanel. I'm trying to use a StackPanel because that seems simpler and should achieve what I'm aiming for.
The issue I'm trying to figure out is how to group the input and label into one unit so they can reside horizontally next to each other, but stack vertically as a pair within the StackPanel.
It's probably best to use a Grid that way you an get the labels and inputs to line up vertically. While it's not impossible with a stack panel it's a whole lot harder. If you set the grid's RowDefinition heights to "Auto" the grid will only be as tall as it needs to be:
<GroupBox>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Label1"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Input1}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Label2"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Input2}"/>
etc.
</Grid>
</GroupBox>
You'll probably need to play around with margins and/or padding and horizontal alignments to get the layout exactly how you want it, but this should give you the control you need to achieve what you want.
you can use a stackpanel with orientation equal to vertical inside your groupbox and inside that stackpanel you can have another stackpanel with orientation equal to horizantal for your label and input just like following sample code.
<GroupBox Header="Sample GroupBox">
<StackPanel Orientation="Vertical">
<StackPanel Name="input1" Orientation="Horizontal">
<Label Content="input1"/>
<TextBox/>
</StackPanel>
<StackPanel Name="input2" Orientation="Horizontal">
<Label Content="input2"/>
<TextBox/>
</StackPanel>
<StackPanel Name="input3" Orientation="Horizontal">
<Label Content="input3"/>
<TextBox/>
</StackPanel>
</StackPanel>
</GroupBox>
One feature you might find useful is grid shared size scope. It can help you align elements in multiple different Grids, by sharing their column\row sizes, like this:
<GroupBox Header="Sample GroupBox">
<StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="firstGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="secondGroup" />
</Grid.ColumnDefinitions>
<Label Content="input11" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="firstGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="secondGroup" />
</Grid.ColumnDefinitions>
<Label Content="input2222222" Grid.Column="0" />
<TextBox Grid.Column="1"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="firstGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="secondGroup" />
</Grid.ColumnDefinitions>
<Label Content="input3333333333333" Grid.Column="0" />
<TextBox Grid.Column="1"/>
</Grid>
</StackPanel>
</GroupBox>
I don't say that it is necessary in the code above, but that is just example. Often, you want to use grid in for example ItemTemplate of ItemsControl, and you want all items to be aligned. Here shared size scope might help.

Stretch Slider to fit Grid/GridViewItem/GridView [C#, XAML]

I really need your help now. I´ve tried a few thousands solutions, but nothing worked for me. This is a part of a page built with Microsoft Visual Studio 2013 for Windows. I want to make to make the Slider (named slider_1) responsive, so it should fill the rest of the page regardless the Screen Solution (cannot use fixed Heights):
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid Grid.Row="0">
.........
</Grid>
<Grid Grid.Row="1" Name="secGrid">
<GridView x:Name="source">
<GridViewItem x:Name="item_1">
<Grid x:Name="container_1">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="name_1" Height="39" Text="123"></TextBlock>
<Button Grid.Row="1" x:Name="toggle_on_1" Content="ON"></Button>
<Slider Grid.Row="2" x:Name="slider_1" Orientation="Vertical" VerticalAlignment="center" HorizontalAlignment="center"/>
<Button Grid.Row="3" x:Name="toggle_off_1" Height="39" Content="OFF"></Button>
</Grid>
</GridViewItem>
</GridView>
</Grid>
Thought I could get it to work by binding the Height of the Slider to the ActualHeight of the "secGrid", but this is not suitable for my purpose, even if it seemed to work well in combination with a converter:
<Slider Grid.Row="2" x:Name="slider_1" Orientation="Vertical" VerticalAlignment="center" HorizontalAlignment="center" Height="{Binding ActualHeight, ElementName=secGrid}"/>
Tried to set VerticalAligment/VerticalContentAligment to "Stretch", but it did not work.
Its important that it is responsive to other Screen Solutions.
Can anybody help me? Do I have to use another type of Element besides the inner Grid named container_1? This is driving me crazy....
PS: Sorry for mistakes in language. I´m german :)
Your Auto sizing grid creates problem for slider scaling as Auto means "size to row content", and * means "size proportional to grid".
Auto means that a row is given as much height as the elements within it require.
The height of * sized row is calculated by allocating space for the auto, and fixed height rows, and then dividing up the remaining space.
below code works fine if I set height to rowdefination 2 or if I set height to grid
<Grid>
<GridView x:Name="source">
<GridViewItem x:Name="item_1" >
<Grid x:Name="container_1">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="name_1" Height="39" Text="123"></TextBlock>
<Button Grid.Row="1" x:Name="toggle_on_1" Content="ON"></Button>
<Slider Grid.Row="2" x:Name="slider_1" Orientation="Vertical" HorizontalAlignment="center"/>
<Button Grid.Row="3" x:Name="toggle_off_1" Height="39" Content="OFF"></Button>
</Grid>
</GridViewItem>
</GridView>
</Grid>

Last grid rows are displayed on top of each other in wpf

I'm adding rows to a grid in the code behind, but each time some of the rows at the end get displayed on top of each other (overlapping; as though they were in the same row). I know that the row numbers I'm setting are not the same, and that each row has a height of auto.
The grid has no fixed height but is within a tab header of fixed height. I'm using a scroll bar with the grid and that works fine (it expands when I add more items), but there are always some number of rows at the end that are overlapping. So it's not like the grid is only accepting a fixed number or is staying at a fixed length. Even if I add a few rows, and the grid only takes up half the screen, the last couple of rows will be overlapping at the end.
Nothing I try to do with the grid seems to change anything - I tried setting the height to auto, to a fixed height, it was all the same. I'm really confused as to what is going on.
Any suggestions would be extremely appreciated. I know a DataGrid might work better here but for now I need to stick with this grid.
This is my xaml code:
<TabControl Grid.ColumnSpan="5" Grid.RowSpan="15" Height="640">
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal" Height="23" VerticalAlignment="Center">
<Image Source= "image.png" Margin="0,-3,0,0" VerticalAlignment="Center" Height="17" />
<TextBlock Margin="5,0,0,0" VerticalAlignment="Center">text</TextBlock>
</StackPanel>
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid Name="myGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="350"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="5"/>
<RowDefinition Height="1"/>
<RowDefinition Height="20"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
</Grid>
</ScrollViewer>
</TabItem/
...
And in the code behind I am adding rows (to the existing ones) in this way:
RowDefinition rowNew1 = new RowDefinition();
rowNew1.Height = new GridLength(1, GridUnitType.Auto);
myGrid.RowDefinitions.Add(rowNew1);
TextBlock tb = new TextBlock();
tb.Text = some_string;
myGrid.Children.Add(tb);
tb.Margin = new Thickness(10, 0, 0, 0);
Grid.SetRow(tb, some_number);
Works fine for me. Make sure the row number you're setting it to is in fact the correct index:
Grid.SetRow(tb, myGrid.RowDefinitions.IndexOf(rowNew1));

C# Change backgroundcolor specific row

I've created a new project from the Grid App (XAML) template (C# Windows Store).
So far I've changed nothing in the template, but I would like to change the backgroundcolor from a specific row in the grid.
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
I would like to change the backgroundcolor from row 0 (which contains the page title).
Any ideas?? Thanks in advance!
This row consits of:
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Grid.Column="1" IsHitTestVisible="false" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
You can't set the background color on the Grid.Row itself, instead set the Background property on whatever occupies this row.
For example
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Background="Red" Grid.Row="0">
<TextBlock>Test</TextBlock>
</Grid>
</Grid>
EDIT:
Updated for Silverlight; TextBlock doesn't have Background so you have to put the control in another Border or grid container which does have background. Code updated to reflect this.
How about inserting border where you need it
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Background="Red" Grid.ColumnSpan="1"></Border>
<TextBlock>Test</TextBlock>
<Border Background="blue" Grid.Row="1" Grid.ColumnSpan="1"></Border>
<TextBlock Grid.Row="1">Test2</TextBlock>
</Grid>
note that you can especify the columns span in case of include more columns

Resize and Keep Controls in Thirds

Is it possible to get controls to automatically divide a space in thirds as the window resizes? It is easy enough to do in code, but I'd like to set the parameters directly in the xaml if possible.
Use the Grid control. It takes up whatever space is available. You can get thirds by doing (assuming you want three columns)
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinitions Width="*"/>
<ColumnDefinitions Width="*"/>
<ColumnDefinitions Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"/>
<Button Grid.Column="1"/>
<Button Grid.Column="2"/>
</Grid>

Categories