【问题标题】:Binding Visibility for DataGridColumn in WPFWPF 中 DataGridColumn 的绑定可见性
【发布时间】:2014-03-31 04:34:42
【问题描述】:

如何通过绑定隐藏 WPF DataGrid 中的列?

这就是我所做的:

<DataGridTextColumn Header="Column header"
                    Binding="{Binding ColumnValue}"
                    Width="100"
                    ElementStyle="{StaticResource DataGridRightAlign}"
                    Visibility="{Binding MyColumnVisibility}" />

这就是我得到的(除了列仍然可见):

System.Windows.Data 错误:2:找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement。 BindingExpression:Path=MyColumnVisibility;数据项=空;目标元素是“DataGridTextColumn”(HashCode=1460142);目标属性是“可见性”(类型“可见性”)

如何修复绑定?

【问题讨论】:

    标签: wpf xaml datagrid visibility


    【解决方案1】:

    首先,DataGridTextColumn(或任何其他受支持的 dataGrid 列)不在DataGrid 的可视化树中。因此,默认情况下它不会继承DataGrid 的DataContext。但是,它仅适用于 Binding DP,不适用于 DataGridColumn 上的其他 DP。

    由于它们不在同一个 VisualTree 中,任何使用 RelativeSource 获取 DataContext 的尝试都不会奏效,因为 DataGridTextColumn 无法遍历到 DataGrid。

    还有其他两种方法可以实现这一点:


    首先使用Freezable 类。 Freezable 对象可以继承 DataContext,即使它们不在可视化或逻辑树中——我们可以利用这一点。

    首先,创建一个继承自 Freezable 和 Data DP 的类,我们可以使用它来绑定 XAML:

    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); }
        }
    
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object),
                                         typeof(BindingProxy));
    }
    

    现在,在 DataGrid 资源中添加它的一个实例,以便它可以继承 DataGrid 的 DataContext 并可以与它的 Data DP 绑定:

        <DataGrid>
            <DataGrid.Resources>
                <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn Visibility="{Binding Data.MyColumnVisibility,
                                                    Source={StaticResource proxy}}"/>
            </DataGrid.Columns>
        </DataGrid>
    

    第二,您可以使用ElementName 或x:Reference 引用XAML 中的任何UI 元素。但是,ElementName 只能在同一个可视化树中工作,而 x:Reference 没有这样的限制。

    所以,我们也可以利用它来发挥我们的优势。在 XAML 中创建一个虚拟 FrameworkElement,并将可见性设置为 collapsed。 FrameworkElement 将从其父容器继承 DataContext,该容器可以是 Window 或 UserControl。

    并且可以在 DataGrid 中使用它:

        <FrameworkElement x:Name="dummyElement" Visibility="Collapsed"/>
        <DataGrid>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Test"
                                    Binding="{Binding Name}"
                                    Visibility="{Binding DataContext.IsEnable,
                                              Source={x:Reference dummyElement}}"/>
            </DataGrid.Columns>
        </DataGrid>
    

    【讨论】:

    • 我喜欢第二种方法。它很容易编写,而且我已经有了另一个对相同可见性的控制,所以我可以给它一个x:Name 并引用它的Visibility 属性。不是很直接,沿途更多地转向侧面,但仍然很简单。我想,当绑定到被引用元素的 DataContext 属性时,你“劫持”了另一个元素以与其他无法访问的 DataGridColumn 共享它的 DataContext,对吧? dummyElement 只是桥梁。
    • @LonelyPixel - 是的,你没看错。我尝试从它的 DataGrid 兄弟孩子劫持 DataContext,因为除非明确设置,否则它们都共享相同的 DataContext。我本可以将 x:Reference 与 DataGrid 本身一起使用,但这会导致循环依赖。
    • +1 为您解答。对不起,我误解了这个问题。通过关于x:Reference的使用——在WPF 4.0中,至少对于Visual Studio 2010仍然可能出现异常:Service provider is missing the INameResolver service,可以忽略。据我了解,它已在 WPF 4.5 中修复。
    • 就个人而言,如果你问我,我喜欢第一种方法。开销只是创建一个类,但是一旦你在你的小猫中拥有它,在 XAML 中编码变得非常容易。我确实经常使用它。
    • @JMIII 不知道,我现在不在任何地方使用它。另外,我不在乎 XAML 编辑器能理解什么(不是很多),只要它最终运行。
    【解决方案2】:
    <Window.Resources>
        <ResourceDictionary>
            <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}" />
        </ResourceDictionary>
    </Window.Resources>
    
    <!-- Necessary for binding to resolve: adds reference to ProxyElement to tree.-->
    <ContentControl Content="{StaticResource ProxyElement}" Visibility="Collapsed" />
    <mch:MCHDataGrid Height="350"
                      AutoGenerateColumns="False"
                      FlowDirection="LeftToRight"
                      ItemsSource="{Binding PayStructures}"
                      SelectedItem="{Binding SelectedItem}">
        <DataGrid.Columns>
             <DataGridTemplateColumn Width="70"
                                     Header="name"
                                     IsReadOnly="True"
                                     Visibility="{Binding DataContext.IsShowName,
                                     Source={StaticResource ProxyElement}}">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <TextBlock Text="{Binding FieldName}" />
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>                   
         </DataGrid.Columns>
    </mch:MCHDataGrid>
    

    视图模型中的绑定属性示例:

    private Visibility _isShowName;
    
    public Visibility IsShowName
    {
        get { return _isShowName; }
        set
        {
            _isShowName = value;
            OnPropertyChanged();
        }
    }
    

    【讨论】:

    • 我猜这已经在一年前提出了。太晚了。
    • 如果要打印当前DataContext的类,使用这个:&lt;TextBlock Text="{Binding DataContext, Source={StaticResource ProxyElement}}"&gt;&lt;/TextBlock&gt;
    • 如果数据上下文实际上不是静态的,但可能会有所不同,则不起作用。在这种情况下,我得到:“System.Windows.Data 错误:3:找不到提供 DataContext 的元素。BindingExpression:(无路径);DataItem=null;目标元素是 'FrameworkElement'(Name='ProxyFrameworkElement');目标创建窗口时,属性为“DataContext”(类型“Object”)”。
    猜你喜欢
    • 2014-10-19
    • 2010-12-06
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 2018-07-28
    • 2013-12-09
    • 2011-08-31
    • 2016-01-31
    相关资源
    最近更新 更多