问题
Under the View-Model-ViewModel pattern for WPF, I am trying to databind the Heights and Widths of various definitions for grid controls, so I can store the values the user sets them to after using a GridSplitter. However, the normal pattern doesn't seem to work for these particular properties.
Note: I'm posting this as a reference question that I'm posting as Google failed me and I had to work this out myself. My own answer to follow.
回答1:
Create a IValueConverter
as follows:
public class GridLengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double val = (double)value;
GridLength gridLength = new GridLength(val);
return gridLength;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
GridLength val = (GridLength)value;
return val.Value;
}
}
You can then utilize the converter in your Binding:
<UserControl.Resources>
<local:GridLengthConverter x:Key="gridLengthConverter" />
</UserControl.Resources>
...
<ColumnDefinition Width="{Binding Path=LeftPanelWidth,
Mode=TwoWay,
Converter={StaticResource gridLengthConverter}}" />
回答2:
There were a number of gotchas I discovered:
- Although it may appear like a double in XAML, the actual value for a *Definition's Height or Width is a 'GridLength' struct.
- All the properties of GridLength are readonly, you have to create a new one each time you change it.
- Unlike every other property in WPF, Width and Height don't default their databinding mode to 'TwoWay', you have to manually set this.
Thusly, I used the following code:
private GridLength myHorizontalInputRegionSize = new GridLength(0, GridUnitType.Auto)
public GridLength HorizontalInputRegionSize
{
get
{
// If not yet set, get the starting value from the DataModel
if (myHorizontalInputRegionSize.IsAuto)
myHorizontalInputRegionSize = new GridLength(ConnectionTabDefaultUIOptions.HorizontalInputRegionSize, GridUnitType.Pixel);
return myHorizontalInputRegionSize;
}
set
{
myHorizontalInputRegionSize = value;
if (ConnectionTabDefaultUIOptions.HorizontalInputRegionSize != myHorizontalInputRegionSize.Value)
{
// Set the value in the DataModel
ConnectionTabDefaultUIOptions.HorizontalInputRegionSize = value.Value;
}
OnPropertyChanged("HorizontalInputRegionSize");
}
}
And the XAML:
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="100" />
<RowDefinition Height="Auto" />
<RowDefinition Height="{Binding Path=HorizontalInputRegionSize,Mode=TwoWay}" MinHeight="50" />
</Grid.RowDefinitions>
回答3:
Another possibility, since you brought up converting between GridLength
and int
, is to create an IValueConverter
and use it when binding to Width
. IValueConverter
s also handle two-way binding because they have both ConvertTo()
and ConvertBack()
methods.
回答4:
The easiest solution is to simply use string settings for these properties so that WPF will automatically support them using GridLengthConverter without any extra work.
来源:https://stackoverflow.com/questions/147908/how-do-i-databind-a-columndefinitions-width-or-rowdefinitions-height