首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何绑定DataGridColumn.Visibility?

如何绑定DataGridColumn.Visibility?
EN

Stack Overflow用户
提问于 2009-06-25 16:53:56
回答 9查看 21.7K关注 0票数 15

我有一个类似于以下帖子的问题:

银光DataGridTextColumn绑定可见性

我需要在Silverlight DataGrid中有一个列,基于ViewModel中的一个值,它是visibile/折叠的。为了实现这一点,我尝试将可见性属性绑定到ViewModel。但是,我很快发现可见性属性不是DependencyProperty,因此不能绑定它。

为了解决这个问题,我尝试将我自己的DataGridTextColumn子类化。使用这个新类,我创建了一个DependencyProperty,它最终推动了对DataGridTextColumn.Visibility属性的更改。如果我不做数据库的话,这很好用。当我将数据库绑定到我的新属性时,它就会失败,只有一个AG_E_PARSER_BAD_PROPERTY_VALUE例外。

代码语言:javascript
运行
复制
public class MyDataGridTextColumn : DataGridTextColumn
{
    #region public Visibility MyVisibility

    public static readonly DependencyProperty MyVisibilityProperty =
        DependencyProperty.Register("MyVisibility", typeof(Visibility), typeof(MyDataGridTextColumn), new PropertyMetadata(Visibility.Visible, OnMyVisibilityPropertyChanged));

    private static void OnMyVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var @this = d as MyDataGridTextColumn;

        if (@this != null)
        {
            @this.OnMyVisibilityChanged((Visibility)e.OldValue, (Visibility)e.NewValue);
        }
    }

    private void OnMyVisibilityChanged(Visibility oldValue, Visibility newValue)
    {
        Visibility = newValue;
    }

    public Visibility MyVisibility
    {
        get { return (Visibility)GetValue(MyVisibilityProperty); }
        set { SetValue(MyVisibilityProperty, value); }
    }

    #endregion public Visibility MyVisibility
}

下面是XAML的一个小片段。

代码语言:javascript
运行
复制
<DataGrid ....>
    <DataGrid.Columns>
        <MyDataGridTextColumn Header="User Name"
                              Foreground="#FFFFFFFF"
                              Binding="{Binding User.UserName}"
                              MinWidth="150"
                              CanUserSort="True"
                              CanUserResize="False"
                              CanUserReorder="True"
                              MyVisibility="{Binding Converter={StaticResource BoolToVisibilityConverter}, Path=ShouldShowUser}"/>
        <DataGridTextColumn .../>
    </DataGrid.Columns>
</DataGrid>

几个重要的事实。

  • 转换器确实是在本地资源中定义的。
  • 该转换器是正确的,它是使用许多其他地方的解决方案。
  • 如果我将MyVisibility属性的{Binding}语法替换为“折叠”,则列实际上会消失。
  • 如果我创建了一个新的DependencyProperty (即字符串Foo),并绑定到它,我也会收到AG_E_PARSER_BAD_PROPERTY_VALUE异常。

有人知道为什么这不管用吗?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2010-09-20 17:50:15

这是我想出的解决方案,用一个小黑客。

首先,您需要从DataGrid继承。

代码语言:javascript
运行
复制
public class DataGridEx : DataGrid
{
    public IEnumerable<string> HiddenColumns
    {
        get { return (IEnumerable<string>)GetValue(HiddenColumnsProperty); }
        set { SetValue(HiddenColumnsProperty, value); }
    }

    public static readonly DependencyProperty HiddenColumnsProperty =
        DependencyProperty.Register ("HiddenColumns", 
                                     typeof (IEnumerable<string>), 
                                     typeof (DataGridEx),
                                     new PropertyMetadata (HiddenColumnsChanged));

    private static void HiddenColumnsChanged(object sender,
                                             DependencyPropertyChangedEventArgs args)
    {
        var dg = sender as DataGrid;
        if (dg==null || args.NewValue == args.OldValue)
            return;

        var hiddenColumns = (IEnumerable<string>)args.NewValue;
        foreach (var column in dg.Columns)
        {
            if (hiddenColumns.Contains ((string)column.GetValue (NameProperty)))
                column.Visibility = Visibility.Collapsed;
            else
                column.Visibility = Visibility.Visible;
        }
    }
}

DataGridColumn及其后代的DataGridEx类添加了一个新的DP,用于根据x:Name隐藏列。

要在您的XAML中使用:

代码语言:javascript
运行
复制
<my:DataGridEx x:Name="uiData"
               DataContext="{Binding SomeDataContextFromTheVM}"
               ItemsSource="{Binding Whatever}"
               HiddenColumns="{Binding HiddenColumns}">
    <sdk:DataGridTextColumn x:Name="uiDataCountOfItems">
                            Header="Count"
                            Binding={Binding CountOfItems}"
    </sdk:DataGridTextColumn>
</my:DataGridEx>

您需要将这些添加到您的ViewModel或您使用的任何数据上下文中。

代码语言:javascript
运行
复制
private IEnumerable<string> _hiddenColumns;
public IEnumerable<string> HiddenColumns
{
    get { return _hiddenColumns; }
    private set
    {
        if (value == _hiddenColumns)
            return;

        _hiddenColumns = value;
        PropertyChanged (this, new PropertyChangedEventArgs("HiddenColumns"));
    }
}

public void SomeWhereInYourCode ()
{
    HiddenColumns = new List<string> {"uiDataCountOfItems"};
}

若要取消隐藏,只需从列表中删除相应的名称,或在未隐藏名称的情况下重新创建该名称。

票数 7
EN

Stack Overflow用户

发布于 2010-10-20 01:05:42

对于这个问题,我有另一个解决方案,它使用类似于您在DataGridTextColumn上找到的“绑定”属性的方法。由于列类是DependencyObjects,所以不能直接对它们进行数据库处理,但是如果添加对实现INotifyPropertyChanged的FrameworkElement的引用,则可以将绑定传递给元素,然后使用依赖项属性通知列绑定已更改。

需要注意的一点是,在列本身而不是网格上绑定可能意味着要使用DataContextProxy访问要绑定可见性的字段(列绑定将默认为ItemSource的作用域)。

代码语言:javascript
运行
复制
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace XYZ.Controls
{
public class ExtendedDataGridTextColumn : DataGridTextColumn
{
    private readonly Notifier _e;

    private Binding _visibilityBinding;
    public Binding VisibilityBinding
    {
        get { return _visibilityBinding; }
        set
        {
            _visibilityBinding = value;
            _e.SetBinding(Notifier.MyVisibilityProperty, _visibilityBinding);
        }
    }

    public ExtendedDataGridTextColumn()
    {
        _e = new Notifier();
        _e.PropertyChanged += ToggleVisibility;
    }

    private void ToggleVisibility(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Visibility")
            this.Visibility = _e.MyVisibility;
    }

    //Notifier class is just used to pass the property changed event back to the column container Dependency Object, leaving it as a private inner class for now
    private class Notifier : FrameworkElement, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public Visibility MyVisibility
        {
            get { return (Visibility)GetValue(MyVisibilityProperty); }
            private set { SetValue(MyVisibilityProperty, value); }
        }

        public static readonly DependencyProperty MyVisibilityProperty = DependencyProperty.Register("MyVisibility", typeof(Visibility), typeof(Notifier), new PropertyMetadata(MyVisibilityChanged));

        private static void MyVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var n = d as Notifier;
            if (n != null)
            {
                n.MyVisibility = (Visibility) e.NewValue;
                n.PropertyChanged(n, new PropertyChangedEventArgs("Visibility"));
            }
        }
    }
}

}

票数 6
EN

Stack Overflow用户

发布于 2009-06-26 20:11:36

datagrid列继承自DependencyObject而不是FrameworkElement。在WPF里这没什么大不了的..。但是在silverlight中,您只能绑定到FrameworkElement对象。因此,当您尝试时,您将得到AG_E_PARSER_BAD_PROPERTY_VALUE的描述性错误消息。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1045014

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档