如何将数据绑定到ColumnDefinition的宽度或RowDefinition的高度?

40

在WPF中,使用视图-模型-视图模型(View-Model-ViewModel)模式时,我尝试绑定网格控件的各种定义的高度和宽度,以便在使用GridSplitter后存储用户设置的值。然而,正常的模式似乎不适用于这些特定属性。

注意:我将此作为参考问题发布,因为谷歌无法帮助我解决问题,我不得不自己解决。接下来会有我的答案。

4个回答

50

创建一个如下所示的IValueConverter

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;
    }
}

然后你可以在绑定中使用这个转换器:

<UserControl.Resources>
    <local:GridLengthConverter x:Key="gridLengthConverter" />
</UserControl.Resources>
...
<ColumnDefinition Width="{Binding Path=LeftPanelWidth, 
                                  Mode=TwoWay,
                                  Converter={StaticResource gridLengthConverter}}" />

如果您正在寻找类似问题的解决方案,可以在此处找到:https://dev59.com/smsz5IYBdhLWcg3wy689 - dzendras
1
Wpf已经有了GridLengthConverter类。直接使用它是否可行? - heltonbiker
5
很抱歉,GridLengthConverter 实现了 ITypeConverter 而不是 IValueConverter 接口,因此不能用作 WPF 绑定转换器。 - Tim Sylvester

23

我发现了一些需要注意的问题:

  1. 虽然在XAML中看起来像是一个双倍数值,但实际上 *Definition 的 Height 或 Width 是一个 'GridLength' 结构体。
  2. 'GridLength' 的所有属性都是只读的,每次更改都必须创建一个新的实例。
  3. 与 WPF 中的其他属性不同,Width 和 Height 默认的数据绑定模式不是 'TwoWay',您需要手动设置它。

因此,我使用了以下代码:

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");
    }
}

还有 XAML:

<Grid.RowDefinitions>
    <RowDefinition Height="*" MinHeight="100" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="{Binding Path=HorizontalInputRegionSize,Mode=TwoWay}" MinHeight="50" />
</Grid.RowDefinitions>

13
GridLength是针对WPF特定的,因此不应该出现在ViewModel层。 - Greg Sansom
5
我认为“在ViewModel中不使用WPF”这种信念是错误的,因为WPF有很多与MVVM模式相关的构造,例如数据绑定本身。你可以说“GridLength是特定于视图的”,而不是特定于ViewModel(除非它是领域问题的一部分,比如数据可视化应用程序,其目的就是布局和显示东西)。但是这当然是有争议的... - heltonbiker
1
@heltonbiker说:“GridLength是特定于VIEW的”,这更准确。除非您的业务逻辑完全或部分涉及UI布局(设计)。 - Ahmed Alejo
抱歉,我不同意。我会使用附加属性。请给我一天时间来完成示例,我可以在哪里放置我的源代码? - Petr Havlát

10
最简单的解决方案是使用字符串设置这些属性,这样WPF会自动支持它们,使用GridLengthConverter而无需额外的工作。

3
真的很棒。String Properties 是解决这个问题最好的 MVVM 模式。 - Behzad

4

另一种可能性是,既然您提到了在GridLengthint之间进行转换,那么可以创建一个IValueConverter并在绑定到Width时使用它。 IValueConverter还处理双向绑定,因为它们具有ConvertTo()ConvertBack()方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接