Control the width of a listbox inside a grid - c#

I have a view. The grid inside the view is divided into 2 columns.
<Grid x:Name="grdView">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
Inside the Auto column(Column 0), I have another view
<Border Grid.Column="0" Style="{DynamicResource BorderStyle}">
<Views:ViewerDataBrowser x:Name="dataBrowser" DataContext="{Binding ViewDataBrowserInstance}" />
</Border>
Inside this view I have a listbox and a data template defined for the list box.
Inside the data template I have 2 rows and 2 textblocks in each of them.
Issue
When the textblock characters are more than the width of the column, the listbox is being stretched and a scroll bar is also displayed. I don't want that to happen. I want the text to be truncated and show ... at the end.
I tried text trimming and text wrapping for the textblock. But it did not work. I also tried to set the width of data template to Auto, but it is not working. The only possible solution working for me is to set the width of the data template to a constant value.
I want the listbox to fit inside the grid and not show the scroll bar even though the text block have lengthy text. Please suggest a solution.

You can get and set the horiztonalScrollBar property of a listBox as described on the MSDN site. When setting the width of the listBox (pre-uwp) you may use device independent pixels (DIPs). Also, instead of using a constant, you may set the width proportional to that of the listBox's container--though not recommended vs DIPs and auto-resizing since certain dimensions behave better.

The issue is caused since the column width of the grid was set to "*".
When I changed the column width to constant, ie the same width as that of the parent, the issue seems to be fixed.
Regarding the truncation of the textblock, I set the textbox trimming property.

Related

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.

Autosize to fit All Content

In WPF, I have the following:
<ListView.View>
<GridView>
<GridViewColumn
Width="Auto"
DisplayMemberBinding="{Binding SomeProperty, Mode=OneWay}"
Header="Type"/>
The problem is that this only auto-sizes the column to the visible content. This is the same behavior when double clicking the header divider as well.
I want it to resize the column according to all content. For contrast, take the Winforms DataGridView equivalent to the current Auto resizing behavior and the equivalent to the desired behavior:
this.dataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells; // Current behavior
this.dataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; // Desired behavior
Is this possible for a WPF ListView?
This question is different than How to autosize and right-align GridViewColumn data in WPF? and others like it because they still trigger the current resizing behavior for visible content and do not address all content.
The problem is the ListView has its ItemsPanel with virtualizing enabled by default. In this mode, only visible content will be rendered and then will trigger the auto-sizing column. So if you don't have many items in your ListView, you can turn off the virtualizing mode via the attached property VirtualizingStackPanel.IsVirtualizing, then it will work expectedly:
<ListView VirtualizingStackPanel.IsVirtualizing="false">
<!-- ... -->
</ListView>
If you don't want to turn off virtualizing, then I don't think there is some easy way to take benefit of the Width="Auto". You may have to implement that feature manually yourself. And technically we need to have knowledge about the largest width to update the column's width accordingly. We can make some for loop every time we need to update the column's width but this is expensive. We can also manage to store the largest width every time a cell has its content changed (this is the better approach). Anyway doing it manually is a pain.

Add textblock to bottom of listview

I need to put a textblock containing result count information at the bottom of a databound listview. It needs to be within the listview's scrollbars but not be affected by the scrollbars (it must always sit at the bottom of the listview).
Because a listview cannot contain a textblock directly I am achieving this by adding some padding at the bottom of the listview and using a negative margin to make a separate textblock appear as though it is part of the listview. The issue with this is that when the listview's horizontal scrollbar is displayed it covers the textblock. I could add code to figure out if the scrollviewer is displayed and then adjust the margins/paddings accordingly BUT at this stage it sounds like a hacky solution.
Is there a better way to achieve this?
Instead of using a ListView.. you can do something like this:
<ScrollViewer>
<StackPanel>
<ItemsControl ItemsSource="{Binding MyCollection}" />
<TextBlock />
</StackPanel>
</ScrollViewer>

WPF Sizing Grid.Row to content

I have a window that uses SizeToContent="WidthAndHeight" and I have a column that has three rows in it. Rows are defines as such:
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
Content is made up of one other Grid panel per above row. Each of those panels contains a label and a ListBox. ListBox dynamically adds or removes its content. So, it might have one item, or it might have 100 items.
My problem is this: When my application starts, the three above-mentioned rows are sized to the content within them. So it looks pretty neat. If the first row contains only one item in the ListBox, it'll size it just enough to fit those items. The other two rows (if overfilled with content) will split the rest of the space in half and make their scroll bars visible if the user wants to see the overflows in each one. However, as soon as I re-size the main window, the three rows will immediately re-size themselves to where each one will be the exact same height, no matter the amount of content in them.
I tried using Height="Auto" in the row definitions of the outer grid; however, that sizes each row to fit the content precisely, thus causing them to overflow off the screen, without ever enabling the scroll bars.
I've tried every setting that I know of (key: know of) and I couldn't solve it. For now I got rid of SizeToContent so that that weird bug wouldn't happen, but the rows are sized proportional to each other no matter the amount of content in them... and I'd like it the other way. I don't want a static height for each of the rows, but rather having them to re-size themselves dynamically, based on the amount of content in them without going off the screen.
Is there a way to fix this?
To get it right you'll have to make your own custom Panel which handles size distribution smarter than the standard Grid. This project may be a good starting point: ConstrainingStackPanel
In your XAML you could bind to a property in your ViewModel
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Row1Height}"/>
<RowDefinition Height="{Binding Row2Height}"/>
<RowDefinition Height="{Binding Row3Height}"/>
</Grid.RowDefinitions>
Then in your ViewModel
public int Row1Height { get; set; }
public int Row2Height { get; set; }
public int Row3Height { get; set; }
And have some calculation that populates that value once you have content.
Assuming I understand your question correctly, have you tried wrapping it inside of a ScrollViewer and turning the scollbar off for the ListView?
I've found that layout rendering in WPF can be both a positive and a crutch. It's sometimes a pain in the butt to get it to work right when it comes to content sizing.
If a ScrollViewer is not an approach you'd like to take, you could easily accomplish something like this through writing some sort of attached behavior (I've done this in the past) but in this case it's way overkill.
Example of ScrollViewer approach:
<Grid>
<ScrollViewer>
<ListView ItemsSource="{Binding Something}" ScrollViewer.VerticalScrollBarVisibility="Hidden">
:
:
:
</ScrollViewer>
</Grid>

programatically set width of a column within a grid

Is it possible to set the width of a column for Grid within Silverlight? I have a grid (not a grid view) with two columns. ColumnA and ColumnB. What I am trying to accomplish is when a user clicks on a button within ColumnA the width of ColumnA is set to .01. ColumnB should then expand the entire width of the grid to fill the remaining area. Similar to how you pin or un-pin a dock panel?
Is this the best approach or should I revert back to a dockpanel and let SL handle it? I'd prefer to manage it myself vs. using a RAD control as I think it is a little bloated for such a small and seemingly simple task.
Another thought I had was to use a gridsplitter but I was unsure as to how to programmatically collapse or expand the column using the gridsplitter? Hence my current predicament. Any suggestions would be greatly appreciated.
Thanks in advance
Give your ColumnDefinition a name via the Name attribute, e.g.:
<ColumnDefinition Width="100" Name="FooColumn"/>
Then you can assign it a new Width in code whenever you want:
FooColumn.Width = new GridLength(1);
(edit: should have used the same name in both places... oops.. you get the idea though)
Try this
<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<sdk:GridSplitter />
</Grid>
LayoutRoot.ColumnDefinitions.First().Width = new GridLength();

Categories

Resources