textbox dynamically change height when the user goes to a new line - c#

In a WPF application I have a textbox. I have set AcceptReturn to true
But I need to make the textbox bigger when the user clicks enter. What I mean is currently when the user clicks on the enter key, the cursor goes to a new line however the text box is still the same height and the above line is now hidden. Can I make the textboxHeight change dynamically depending on it's content?
Thanks
PS: I cannot use textarea I need to stay with the textboxes

I would suggest to keep it a current size and use the vertical scrollbar. But, if you're doing something that really requires it, place your TextBox into a Grid. Set the Grid row height to auto. Set the Height of the TextBox to Auto. Set the VerticalAlignment of the textbox to Stretch. In the code below I left the scrollbar settings in. You can change those how you see fit.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="scriptTextBox" Margin="10" Height="Auto" Width="Auto" FontFamily="Consolas, Courier New"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
MaxLines="9999" AcceptsReturn="True" AcceptsTab="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{Binding Path=Script, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
</Grid>

You say you need to use Textboxes. Can you at least use an overriden Textbox? This worked pretty well in my testing:
public class AutoHeightTextbox : TextBox {
protected override Size ArrangeOverride(Size arrangeBounds) {
Size unboundSize = new Size(this.Width, double.PositiveInfinity);
Size textSize = base.MeasureOverride(unboundSize);
this.Height = textSize.Height;
return base.ArrangeOverride(arrangeBounds);
}
}

Related

WPF datagrid MinWidth=auto MaxWidth=*

I have a seemingly simple use case but its been troubling me for hours
I have a grid with two rows and two columns, the first column should take all the available width and the second column should take the width it requires. The problem is with the 'required width' of the second column. This column contains a datagrid in the top row and a label (for simplicity) in the bottom row.
The datagrid has two columns which should both take up 50% width of the datagrid.
I want:
If the label is wider than the datagrid the datagrid should scale up (and NO semi column MAY appear at the end of the datagrid filling up the remaining space)
If the datagrid is wider than the label, the column may not be
smaller than the required size for the datagrid.
The problem:
If I set the datagrid columns to take all available space (width='*') it works if the label is bigger than the datagrid (but if the label is smaller the datagrid shrinks to the width of the label, and not al text is readable)
If I set the columns to 'autosize' it works is the label is smaller than the datagrid (but if the label is bigger the 'semi' column appears (and it really hurts my eyes)).
The code:
x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid Grid.Column="1" Name="grid">
<!-- Change column width to simulate the problemn-->
<DataGrid ItemsSource="{Binding Items}" ColumnWidth="*" RowHeaderWidth="0" Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}"/>
</Grid>
<!-- change label text to simulate problemn-->
<Label Grid.Row="1" Grid.Column="1" Content="x"/>
</Grid>
The binding to the actual width of the grid is to have the columns scale up correctly
The Items is a List of objects (which contain two string values)
This is dirty and would probably cause me to rethink my design, but it works based on your requirements. I'm not sure how else to achieve this without creating a custom control or greatly modifying the DataGrid default template, but here goes.
Change your DataGrid styling to this and give names to both the Label and the DataGrid.
<DataGrid Name="dg" ItemsSource="{Binding Items}" CanUserResizeColumns="False"/>
///
<Label Grid.Row="1" Grid.Column="1" Content="x" Name="label"/>
Then create a ContentRendered event for your MainWindow.
Title="MainWindow" Height="450" Width="800" Name="mw" ContentRendered="Mw_ContentRendered">
Now in the render event, manually resize columns after the render occurs. You can't assign a star to the width as it won't resize correctly, so you need to divide your widths evenly base on column count.
private void Mw_ContentRendered(object sender, EventArgs e)
{
//Loop through columns and resize
for (int x = 0; x < dg.Columns.Count; x++)
{
double div = dg.ActualWidth / dg.Columns.Count;
double add = div - dg.Columns[x].ActualWidth;
if (add < 0) { div += -add; }
dg.Columns[x].Width = new DataGridLength(div);
}
}
EDIT: Updated width logic to account for uneven widths
I ended up creating my own user control.
This was relatively easy as I know at design time which rows I will have in the 'datagridview'.
Tronald's suggestion works, provided that the data does not change after rendering (mine does, both the datagrid contents and the 'label' change based on selections made in the rest of the application).
I still think that the 'Width="*" MinWidth="auto"' combination should be possible for a datagrid so If anybody has a solution.

Get current Rendered width of Grid column Wpf

I have a Grid that has some column defined and Column width is also defined in xaml.
<Border Grid.Row="2" BorderThickness="2" BorderBrush="#001732"
Width="{Binding ActualWidth, ElementName=ParentContainer}">
<Grid Name="DataGrid" Width="{Binding ActualWidth, ElementName=ParentContainer}"
Style="{StaticResource GridStyle}">
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
</Grid>
</Border>
now if i change the size of window the column width changes automatically. and i am trying to get the changed latest width with this code.
public void CoulmnWidthSetter()
{
_columnWidth = DataGrid.ColumnDefinitions[4].Width.Value;
foreach (var col in DataGrid.ColumnDefinitions)
{
_totalColumnsWidth = _totalColumnsWidth + col.Width.Value;
}
}
and calling the Column width setter method in below Event.
private void ParentContainer_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
CoulmnWidthSetter();
}
or i have tried to call this method in Window size changed event also. But still it always give me that hard coded 50 width value why ?
In WPF Width and ActualWidth are two different things.
What you're looking for here is the ActualWidth of your ColumnDefinitions.
The ActualWidth is a double value that represents that length at that moment in time.
Signature:
public double ActualWidth { get; }
The Width is a GridLength type; that can be set by various means; including hard coded values, Star values, or Auto. You set the Width (a GridLength type) to give the ColumnDefinition the information needed to dynamically adjust itself accordingly or to remain constant. It is not intended to provide you with the current value but instead give the owner an expressive way of setting it's values.
Examples:
columnDefinition.Width = new GridLength(50); //Hard coded to 50
columnDefinition.Width = new GridLength(50, GridUnitType.Star); //dividend of remaining space allocated at 50.
//In other words; any other Star values will be divided in Width based on the remaining Grid size and the Star value given.
//A star value of 25* in another ColumnDefinition will make it half the length of the 50* and a value of 100* will make it twice the 50* or the 50* half of the 100*.
//Either way you look at it; the total remaining Width of the space provided by the panel gets divided out to the Star Columns and the dividend they get is based on their portion of the Star. 50* for all Columns will make them all equal.
columnDefinition.Width = GridLength.Auto; //Adjusts to the needed width dynamically. As your content grows so does the Width.
Width is also a DependencyProperty so it allows Binding and must be set on the UI thread.
Also; just a suggestion: You shouldn't need to set the size that way just because your view is dynamically changing size. This is what the * star is for in the value setting. There are also other means of doing this built in but without knowing exactly why you're doing it; have at it.

ExtentWidth of TextBox not set correctly

I recently experienced a strange behavior of text boxes.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Test"/>
<TextBox Grid.Column="1" TextWrapping="Wrap" Text="testtesttesttesttesttesttesttesttesttesttest"/>
<Control Grid.Row="1" Grid.ColumnSpan="2" Width="280"/>
</Grid>
In this example code I have a Grid with 2 rows and 2 columns. The 2nd column is set to a fixed width. The TextBox has TextWrapping set to Wrap.
In the second row I have a Control with a fixed width that is higher than the Grid would normally be. This increases the ActualWidth of the second column from 200 to about 250.
The actual width of the TextBox also increases to match the new width of the column.
When I now add a long string to the text box the text, it doesn't use the full width of the TextBox but instead wraps way to early and leaves about 40 pixels at the end of the TextBox empty.
I've found out that the TextBox has a readonly ExtentWidth property. This property is responsible for the wrapping. In my example the values of the ExtentWidth is about 180, which is the 200 from the width of the grid column minus margins and paddings.
What can I do to fix the wrapping in the TextBox?
EDIT: This question is not a duplicate of Looking for explanation for WPF Grid ColumnSpan behavior.
That question explains what happens to the Widths of the grid columns. But it doesn't answer the question regarding the wrapping behavior of the TextBox.
I honestly don't understand the "why" part, but until someone provides a meaningful explanation, here are some workarounds:
Set an explicit width on the TextBox
Set MaxWidth on the column instead of Width
Bind the width of the TextBox to that of another element inside the same column. e.g:
<TextBox Grid.Column="1" Width="{Binding ActualWidth, ElementName=rect}" ... />
<Rectangle Grid.Column="1" x:Name="rect"/>
Note that the last one is the only usable workaround if you need to be able to change the column width at runtime and want the TextBox (and the wrapping) to change with it.

How to set button in side stackpanel to right edge in windows 10 universal app development

I an new to windows app development,i searched for this but not found any where.I need the button at right edge and Stretch the textbox till buttons start.But I am unable to set the button to Right edge.
How to acheve this.
A stackpanel works like a container. If you define layout properties on your stackpanel, then the objects inside your stackpanel cannot be displayed outside of the stackpanel's limits.
For example :
If I set my row and column number in my stackpanel,
<StackPanel Grid.Row="0" Grid.Column="2" Name="Version" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top">
<Label Grid.Column="4" Grid.Row="6" Name="Ver" Content="V." HorizontalAlignment="Right" />
<TextBlock Name="Vers" Text="1.0" TextAlignment="Right" />
</StackPanel>
Then the row/column properties set on my label are ignored and the 'HorizontalAlignment="Right"' will place my label on the right side of the stackpanel, not the grid.
A solution may be to remove your button from your stackpanel, you are then free to place your button anywhere on the grid.
Another solution can be to expand your stackpanel's limits.
To do so, you can use the Grid.ColumnSpan property or simply set your stackpanel on the right of the grid.
Hope that helped.

Scrollbar "dragger" size not changing when maximum value set

Should the "dragger" on a scroll bar be increasing as I set the .MaximumValue property of the scroll bar to a smaller value?
I am using a wpf scroll bar.
Please let me know if you need anymore information.
Xaml:
<ScrollBar Grid.Row="0" HorizontalAlignment="Right" Name="scrollBar1" VerticalAlignment="Stretch" Width="18" Scroll="scrollBar1_Scroll" SmallChange="1" LargeChange="5" />
Code to set maxvalue:
scrollBarMaximum = numberOfRecords - numberOfRecordsToLoad;

Categories

Resources