【问题标题】:How to hide wpf datagrid columns depending on a property如何根据属性隐藏wpf datagrid列
【发布时间】:2011-10-15 00:38:06
【问题描述】:

我有以下 WPF 示例程序:

Xaml:

<Window x:Class="AncestorArie.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVis" />
    </Window.Resources>
    <Grid>
        <DataGrid AutoGenerateColumns="False" Name="Blumen" 
                  ItemsSource="{Binding Leaves}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Color}" 
                                    Header="Farbe" Width="160" />
                <DataGridTextColumn Binding="{Binding Size}" 
                                    Header="Größe" Width="60"
                                    Visibility="{Binding Path=DataContext.Flag, 
                                                RelativeSource={RelativeSource Findancestor, 
                                                AncestorType={x:Type Window}}, 
                                                Converter={StaticResource BoolToVis}}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

后面的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Flowers rose = new Flowers();
        rose.Leaves = new ObservableCollection<Leaf>();

        rose.Flag = false;

        Leaf L1 = new Leaf();
        L1.Color = "rot";
        L1.Size = 3;
        rose.Leaves.Add(L1);

        Leaf L2 = new Leaf();
        L2.Color = "gelb";
        L2.Size = 2;
        rose.Leaves.Add(L2);

        this.DataContext = rose;            
    }
}

模型类是:

public class Leaf
{
    public string Color { get; set; }
    public int Size { get; set; }
}

public class Flowers
{
    public bool Flag { get; set; }
    public ObservableCollection<Leaf> Leaves { get; set; }
}

如您所见,如果 Flag 属性设置为 false,我想隐藏第二个数据网格列。但它不起作用。我在 Visual Studio 输出窗口中收到以下绑定错误:

System.Windows.Data 错误:4:找不到绑定源 参考'RelativeSource FindAncestor, AncestorType='System.Windows.Window',AncestorLevel='1''。 BindingExpression:Path=DataContext.Flag;数据项=空;目标元素 是 'DataGridTextColumn' (HashCode=44856655);目标属性是 “可见性”(类型“可见性”)

关于Visibility 属性的代码有什么问题?

【问题讨论】:

    标签: c# wpf xaml data-binding datagrid


    【解决方案1】:

    如果您要自动生成列,则可以使用一个事件:

    https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.datagrid.autogeneratingcolumn?view=net-5.0

    我将更改为自动生成的列和此事件以解决几个问题!也可以用来改变列上的Header。

    【讨论】:

    • 鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防外部资源无法访问或永久离线。
    【解决方案2】:

    我更喜欢使用Freezable 的更优雅的方法。

    <Window.Resources>
    
        <DiscreteObjectKeyFrame x:Key="FlagKey" Value="{Binding Flag}"/>
    
    </Window.Resources>
    
    
    <DataGridTextColumn ... Visibility="{Binding Value, Source={StaticResource FlagKey}, ...}" />
    

    【讨论】:

    • AnjumSKhan :确实非常好。干净优雅。谢谢
    • 这也适用于绑定代理不起作用的情况。刚刚试了一下——谢谢!
    • 在 .Net 5 中测试过,效果很好。另外,它允许我基于一个公共属性一次隐藏几列。简单的智能解决方案。额外提示:如果要将布尔值转换为可见性,请使用 DiscreteObjectKeyFrame.Value 转换器:&lt;DiscreteObjectKeyFrame x:Key="FlagKey" Value="{Binding Flag, Converter={StaticResource BooleanToVisibilityConverter}}" /&gt;
    【解决方案3】:

    H.B. 提出的解决方案。真的很好,有真正的 WPF MVVM 精神。尽可能使用它。

    在我的特殊情况下出了点问题,所以我想出了不同的方法,因为我的项目不是严格的 MVVM,所以我可以使用编码解决方案。

    在 CustomView.xaml 中分配给列的名称:

    <DataGrid>
        <DataGrid.Columns>
            <DataGridTemplateColumn x:Name="MachinesColumn" ... />
            ...
    

    在 CustomView.xaml.cs 中,我们有一个简单的属性可以直接改变列的可见性:

    public Visibility MachinesColumnVisible
    {
        get { return MachinesColumn.Visibility; }
        set
        {
            if (value == MachinesColumn.Visibility)
                return;
            MachinesColumn.Visibility = value;
        }
    }
    

    【讨论】:

      【解决方案4】:

      DataGridTextColumn 上的可见性不是 DependencyProperty,不能进行数据绑定。使用 DataGridTemplateColumn 并绑定模板内控件的可见性。

      编辑:实际上,此声明仅适用于 Silverlight。有关详细信息,请参阅此其他 SO 问题。

      How to bind DataGridColumn.Visibility?

      我在这里询问了判断属性是否为依赖项的最简单方法。

      How can I most easily determine whether a property is a dependency property?

      【讨论】:

      • 感谢您的回答。你能告诉我如何在 Xaml 中识别一个属性是否是依赖属性吗?
      • 我得到一个 绑定错误 令人困惑(请参阅我的编辑)。看起来 WPF 会尝试将 Visibility 绑定到属性。如果一个属性根本无法绑定,我预计会出现不同的错误——比如“无法绑定”之类的。
      • 其实是DP,否则会编译出错。
      • @H.B.我的错。这看起来像是 Silverlight 和 WPF 之间的区别。
      • 感谢您的进一步解释!
      【解决方案5】:

      数据网格中的列是一个抽象对象,它不会出现在可视化树中,因此您不能使用RelativeSource-binding,ElementName 也不起作用,因为它找不到管理 FrameworkContentElement,所以您在一种绑定。

      一种可行的方法是通过Sourcex:Reference,因为您需要命名您的窗口并将列移动到其资源以避免循环依赖错误:

      <Window Name="_window" ...>
          <Window.Resources>
              <DataGridTextColumn x:Key="ThatPeskyColumn"
                                  Binding="{Binding Size}"
                                  Visibility="{Binding DataContext.Flag, Source={x:Reference _window}, Converter={StaticResource BoolToVis}}"/>
          </Window.Resources>
          <!-- ... -->
              <DataGrid AutoGenerateColumns="False" Name="Blumen" 
                        ItemsSource="{Binding Leaves}">
                  <DataGrid.Columns>
                      <StaticResource ResourceKey="ThatPeskyColumn"/>
                      <!-- ... -->
      

      非常有趣。

      【讨论】:

      • 我知道,我参加聚会有点晚了,但是谢谢,伙计!附言我讨厌 DataGrid 开发者。
      • 自从我从 .NET 4 升级到 4.5.2 后,我似乎无法让它工作。有谁知道为什么?
      • @CamHart:你知道如何调试绑定吗?
      • @H.B.不,我没有。我试图启动第二个 VS,并附加到第一个 VS 上运行的进程。但我永远无法触发任何错误。不过我确实找到了解决方案,stackoverflow.com/questions/34817417/…
      • @H.B.如果绑定是在单独的 xaml 文件的单独 ResourceDictionary 中的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      • 2020-05-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多