WPF bug? Grid's column does not accommodate ListBox scrollbar - wpf

In the following example, the leftmost column's width does not increase to accommodate the ListBox's scrollbar that appears when the UserControl's height is decreased:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Example">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.ColumnSpan="2">Example text</TextBlock>
<ListBox Grid.Row="1" Grid.Column="0">
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
<ListBoxItem>Three</ListBoxItem>
<ListBoxItem>Four</ListBoxItem>
<ListBoxItem>Five</ListBoxItem>
</ListBox>
<Expander Grid.Row="1" Grid.Column="1" Header="Expander" />
</Grid>
</UserControl>
When the TextBlock with the ColumnSpan attribute is removed the column resizes as expected. Is this a bug in WPF?

It appears this is a known bug with the ListBox scrollbar and the WPF Grid. Microsoft also notes they will probably not have this fixed in 4.0.

Related

Grid column width not respected when inside of a ScrollViewer

I've one view of mine which displays a control based on some factory:
<dxdo:LayoutPanel ShowCaption="False">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ContentControl Margin="15,5,10,10" Content="{Binding SomeObject, Converter={StaticResource ModelToViewModelConverter}}" ContentTemplateSelector="{StaticResource ConventionBasedDataTemplateSelector}" />
</ScrollViewer>
</dxdo:LayoutPanel>
One of the control that is displayed contains one Grid, with some specific controls.
Basically I've the 2 firsts columns that are used with specific sizes and a third one to take the remaining available space, and then some components that takes the whole width:
<UserControl x:Class="ch.VibroMeter.Xms.Configurators.Common.Views.Machinery.MachineStates.CustomMachineStateView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
<!-- skipping namespace declaration -->
mc:Ignorable="d" >
<UserControl.Resources>
<converters:DrawingColorToMediaColorConverter x:Key="DrawingColorToMediaColorConverter" />
</UserControl.Resources>
<StackPanel>
<controls:TitleBlock Title="{Binding State.Name}" Margin="0,0,0, 5" />
<subControls:MainProperties Model="{Binding State, ValidatesOnNotifyDataErrors=False}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Source={x:Static common:Constants.COLUMN_LABEL_WIDTH}}" />
<ColumnDefinition Width="{Binding Source={x:Static common:Constants.COLUMN_FIELD_WIDTH}}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!--Color-->
<TextBlock Grid.Row="0" Grid.Column="0" Text="Color" Margin="3" />
<dxe:PopupColorEdit Grid.Row="0" Grid.Column="1" ShowAlphaChannel="False" Margin="3" Color="{Binding State.Color, Mode=TwoWay, Converter={StaticResource DrawingColorToMediaColorConverter}}" />
<!--Separator-->
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Margin="0,12,0,12"/>
<!--Measurements Filters -->
<TextBlock Grid.Row="2" Grid.Column="0" Text="Conditions" FontSize="18" Margin="3,3,3,12"/>
<measurementsFilterConfigurationControl:MeasurementsFilterConfigurationControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3"
FilterRuleTypes="{Binding AvailableFilterRuleTypes}"
MeasurementsFilterConfiguration="{Binding State.FilterConfiguration}"
Margin="0 10 0 0"/>
</Grid>
</StackPanel>
</UserControl>
I found out that the columns sizes are not at all respected. The COLUMN_LABEL_WIDTH is 200, but the ActualWidth of my TextBlock with "Color" text is more than 300.
After some investigation, I found out that if I remove the ScrollViewer or set the HorizontalScrollBarVisibility to Disabled, it works, but then when I resize the window too much(for this control, less than COLUMN_LABEL_WIDTH +COLUMN_FIELD_WIDTH), I don't get the desired scrollbars.
I understand that when I use a scrollViewer, I will get an infinite available size, but I would have thought this space would have been put in the column with the * size.
I cannot removing the scrollViewer Auto, because some components(like the MeasurementsFilterConfigurationControl in this view) might get hidden when resizing the windows).
I don't have access to the ScrollViewer in this component.
So how would you fix this?

How to resize the usercontrol in wpf resizing

In my wpf project I have one main window(Mainwindow.xaml) file and remaining all windows are user controls. If I click any menu of the mainwindow.xaml then the corresponding usercontrols will appear in the mainwindow.xaml form.
My requirement is, when the usercontrol window is resized, I need to resize all controls width (i.e textboxes,comoboxes,..etc). How can I achieve this.
First of all, the components you need to resize dynamically should not have fixed sizes. You should put everithing into Grid and set width/height to "Auto"/"x*"/ Alignment to stretch...
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/><!--2/5 of total height-->
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="1" Grid.Row="1">Text </TextBlock>
<TextBox Grid.Column="2" >Enter</TextBox>
<TextBox Grid.Row="2" Grid.ColumnSpan="2">Button 5 Button 5 Button 5 Button 5</TextBox>
</Grid>
</UserControl>
Main
<Grid Width="Auto" HorizontalAlignment="Stretch">
<ContentControl ..." />
</Grid>

Stretch a Grid inside a ListView in XAML

I have a Grid inside a ListView. If I place the Grid outside of the ListView, it correctly stretches to fill the screen. If I place it within the ListView, it does not. Here's my code
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ListView HorizontalContentAlignment="Stretch">
<ListViewItem>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0">Title</TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1">Text</TextBlock>
<Button Grid.Column="1">Pin</Button>
</Grid>
</ListViewItem>
</ListView>
</Grid>
How do I get the Grid it to stretch and fill the ListView?
You probaby need to set the HorizontalContentAlignment of the ListViewItem to Stretch.

WPF Element Binding With Dynamically Generated UI Elements

I have a page in which I have a grid with 2 columns, one accommodating 80* width and the other accommodating 20*. Beneath the grid is a stack panel to which I load UI elements (child stack panels) at runtime.
My objective is to bind the widths of the stackpanels to the columns of the grid. This works perfectly and the stackpenels resize if the dynamic content is mocked to be static in the design view. But when the application is run, the bindings fail and the widths are not bound.
Is there any way to refresh the bindings so that I can notify the stackpanels to refer the widths of the grid and configure its's size?
Updated:
This is what my XAML looks like:
<Page x:Class="WPFTestApp.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="resizeGrid"
Grid.Column="0" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="leftColumn"
Width="80*" />
<ColumnDefinition x:Name="rightColumn"
Width="20*" />
</Grid.ColumnDefinitions>
</Grid>
<StackPanel x:Name="contentPanel"
Grid.Column="0" Grid.Row="0" >
<!-- Dynamic StackPanels are added here -->
</StackPanel>
</Grid>
</Page>
In my code, I create StackPanel elements and add it to the contentPanel by saying:
contentPanel.Children.Add(...);
Unfortunately, I HAVE to use StackPanels here. :-(
The markup of a dynamically created StackPanel element is as follows (note that I use a Binding to the grid already in the XAML):
<StackPanel x:Name="element01"
Orientation="Horizontal"
Width="{Binding ElementName=resizeGrid, Path=ActualWidth}" >
<StackPanel x:Name="leftPanel"
Orientation="Vertical"
Width="{Binding ElementName=leftColumn, Path=ActualWidth}">
<!-- Content goes here -->
</StackPanel>
<StackPanel x:Name="rightPanel"
Orientation="Vertical"
Width="{Binding ElementName=rightColumn, Path=ActualWidth}">
<!-- Content goes here -->
</StackPanel>
</StackPanel>
The XAML code for my dynamic StackPanel elements are generated through an XSLT transformation
Note the xmlns:x namespace dynamic StackPanel. This also has to be done because of it being generated through XSLT
As far as I know setting the Width of a StackPanel with Orientation="Horizontal" will have no effect. The size of a StackPanel does not exceed the size of its content in its oriented direction.
Why do you "HAVE" to use StackPanels here? You almost certainly want DockPanels, given your objective. You won't have to bind or set anything, because the DockPanel will fill the cell automatically.
Try binding the ActualWidth instead of Width.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="resizeGrid"
Grid.Column="0" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="leftColumn"
Width="{Binding ElementName=contentPanel, Path=ActualWidth}" />
<ColumnDefinition x:Name="rightColumn"
Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<StackPanel x:Name="contentPanel"
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" >
<StackPanel Background="Yellow" Width="100" Height="25" />
<StackPanel Background="Green" Width="120" Height="25" />
<StackPanel Background="Red" Width="140" Height="25" />
<TextBlock Background="Gray" Text="{Binding ElementName=contentPanel, Path=ActualWidth}" />
</StackPanel>
</Grid>
The following changes I have done above:
1) Set the leftColumn to the ActualWidth of the contentPanel
2) Set the rightColumn to *
3) contentPanel HorizontalAlignment should be changed other then Stretch. Here I have changed it to Left
HTH
I found a solution for this issue. (Sorry for the late response)
What I did was, I cut and pasted the "resizeGrid" Grid control into the "contentPanel" Stackpanel.
As I mentioned above, the contents within the contentPanel are generated through an XSLT transformation and this surely creates a namespace reference issue. I noticed "element not found..." message in the Output window whenever this Window is loaded - this proved me right.
Inserting the "resizeGrid" into the "contentPanel" helped because then both the controls are within the same namespace and can be referenced for a PropertyBinding using "ElementName" attribute.
Thank you for your support! :-)

Centering a WPF control

I have a window where I add a new UserControl to (with an image), I simply want to center the control in the middle of the screen (both vertically and horizontally). I can only get the vertical one to work. I'm gonna swap content in the DockPanel from my CodeBehind and want to show this startup screen before I start doing my slideshow UI, this means that the content is set from the CodeBehind.
My Window:
<Window x:Class="GreenWebPlayerWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="512" Width="853" WindowStyle="None" WindowState="Maximized" WindowStartupLocation="CenterScreen">
<DockPanel Width="Auto" Height="Auto" Name="TransitionContainer" Background="Black" Margin="0" LastChildFill="True"></DockPanel>
</Window>
My UserControl:
<UserControl x:Class="GreenWebPlayerWPF.FrontPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel Background="Black">
<Image Name="image1" Stretch="None" Source="/GreenWebPlayerWPF;component/gw.png" />
</DockPanel>
</UserControl>
Please note that I'm using maximized/full screen.
Use a Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Replace with your UserControl -->
<Button Content="Foo" Grid.Column="1" Grid.Row="1"/>
</Grid>
You can dock it inside your DockPanel (if you must have a DockPanel there) to stretch. And, of course, while the above is all markup, you can just as easily create such a grid from code.
I keep running into this problem when trying to center elements on the page.
The problem with the StackPanel is that HorizontalAlignment has no effect when the Orientation is Horizontal and VerticalAlignment no effect when Orientation is Vertical. So you keep banging your head trying to set values with no effect. It is not illogical that it works this way but it would be good if this was reported as an error.
The solution I found is to have two imbricated StackPanels one centered horizontally and the other vertically as shown below. Finding the size of the parent is needed to size the intermediate panel otherwise it would be flat and its content hidden - an absolute value would work as well. Although not a panacea itis a bit less verbose than using a grid.
<StackPanel Background="Bisque" Orientation="Vertical" Width="300" Height="300" >
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=StackPanel}, Path=ActualHeight}">
<StackPanel VerticalAlignment="Center" Width="200" Height="60" Background="Blue">
</StackPanel>
</StackPanel>
</StackPanel>
It's quite an old one, but centring a control is now as simple as:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Height="350" Width="600">
<TextBox />
</StackPanel>
</Grid>

Resources