将可见性绑定到 WPF 数据网格中的布尔值



我知道,由于 DataGrid 列不是可视化树的一部分,因此无法将列的可见性属性直接绑定到 VM 中的布尔属性。你必须以另一种方式去做。以下是我的做法:

public class LocalVm
{
    public static ObservableCollection<Item> Items
    {
        get
        {
            return new ObservableCollection<Item>
            {
                new Item{Name="Test1", ShortDescription = "Short1"}
            };
        }
    }
    public static bool IsDetailsModeEnabled
    {
        get { return true; }
    }
}
public class Item : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    private string _shortDescription;
    public string ShortDescription
    {
        get
        {
            return _shortDescription;
        }
        set
        {
            _shortDescription = value;
            OnPropertyChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML:

<Window x:Class="Wpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Wpf"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        d:DataContext="{d:DesignInstance Type=local:LocalVm}"
        Title="MainWindow" Height="350" Width="525" 
        Name="MyWindow">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVis" />
        <DataGridTextColumn x:Key="ThatPeskyColumn"
                            Binding="{Binding Size}" 
                            Visibility="{Binding DataContext.IsDetailsModeEnabled, 
                            Source={x:Reference MyWindow}, 
                            Converter={StaticResource BoolToVis}}"/>
    </Window.Resources>
    <Grid>
        <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" />
                <StaticResource ResourceKey="ThatPeskyColumn"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

但是,在我的 xaml 窗口中,"可见性"属性上出现错误:"对象引用未设置为对象的实例"。如果我删除源和转换器部分,错误会出现,但它没有正确绑定。我做错了什么?

提前致谢

正如我从您提供的代码中看到的那样,IsDetailsModeEnabled 属性是静态的。在这种情况下,若要绑定到静态属性,只需将 VM 创建为静态资源,绑定到其静态属性,稍后将其设置为窗口数据上下文:

<Window.Resources>
    <local:LocalVm x:Key="vm" />
    <BooleanToVisibilityConverter x:Key="BoolToVis" />
    <DataGridTextColumn x:Key="ThatPeskyColumn"
                        Binding="{Binding ShortDescription}" 
                        Visibility="{Binding Path = IsDetailsModeEnabled, 
                        Source={StaticResource vm}, 
                        Converter={StaticResource BoolToVis}}"/>
</Window.Resources>
<Window.DataContext>
    <StaticResource ResourceKey="vm"/> 
</Window.DataContext>

另一方面,在这种情况下,更经典的方法是使用代理可冻结对象,如下所述:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
    #endregion
    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }
    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

XAML

<Window.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
    <BooleanToVisibilityConverter x:Key="BoolToVis" />
    <DataGridTextColumn x:Key="ThatPeskyColumn"
                        Binding="{Binding ShortDescription}" 
                        Visibility="{Binding Path=Data.IsDetailsModeEnabled, 
                        Source={StaticResource proxy}, 
                        Converter={StaticResource BoolToVis}}"/>
</Window.Resources>

最新更新