Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Silverlight 如何绑定DataGridColumn.Visibility?_Silverlight_Datagrid_Binding_Visibility - Fatal编程技术网

Silverlight 如何绑定DataGridColumn.Visibility?

Silverlight 如何绑定DataGridColumn.Visibility?,silverlight,datagrid,binding,visibility,Silverlight,Datagrid,Binding,Visibility,我有一个类似以下帖子的问题: 我需要Silverlight DataGrid中的一列根据ViewModel中的值进行可视/折叠。为了实现这一点,我尝试将Visibility属性绑定到ViewModel。但是,我很快发现Visibility属性不是DependencyProperty,因此它无法绑定 为了解决这个问题,我尝试将自己的DataGridTextColumn子类化。通过这个新类,我创建了DependencyProperty,它最终将更改推送到DataGridTextColumn.Vis

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

我需要Silverlight DataGrid中的一列根据ViewModel中的值进行可视/折叠。为了实现这一点,我尝试将Visibility属性绑定到ViewModel。但是,我很快发现Visibility属性不是DependencyProperty,因此它无法绑定

为了解决这个问题,我尝试将自己的DataGridTextColumn子类化。通过这个新类,我创建了DependencyProperty,它最终将更改推送到DataGridTextColumn.Visibility属性。如果我不进行数据绑定的话,这很有效。当我数据绑定到我的新属性时,它失败了,出现了一个AG_E_PARSER_BAD_property_VALUE异常

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的一个小片段

<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}语法替换为“Collapsed”,那么该列实际上会消失
  • 如果我创建一个新的DependencyProperty(即字符串Foo),并绑定到它,我也会收到AG_e_PARSER_BAD_PROPERTY_VALUE异常

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

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

从MyDataGridTextColumn类中,您可以获得周围的DataGrid。 然后将ViewModel从DataGrid的DataContext中取出,并向ViewModel的PropertyChanged事件添加一个处理程序。在处理程序中,您只需检查属性名及其值,并相应地更改列的可见性。 这不是最好的解决方案,但它应该会起作用;)

克里斯·曼奇尼

您不会创建绑定到数据网格列的“binding”属性。好吧,您可以编写“{Binding User.UserName}”,但它不会创建绑定,因为(正如zachary所说)datagrid列不会从FrameworkElement继承,也没有SetBinding方法。 所以表达式“{Binding User.UserName}”只是创建绑定对象并将其分配给列的Binding属性(该属性是绑定类型)。
然后datagrid column在生成单元格内容时(GenerateElement-protected方法)使用此绑定对象在生成的元素(例如,在生成的TextBlock的Text属性上)上设置绑定,这些元素是框架元素

我不知道这会有多大帮助,但我自己在最新的项目中遇到了数据网格列缺少依赖属性的问题。我所做的是在网格列视图模型中创建一个事件,然后在客户机中组装网格时,使用闭包将网格列订阅到列视图模型。我的特别问题是宽度。它从轴网柱的视图模型类开始,类似于以下伪代码:

public delegate void ColumnResizedEvent(double width);

public class GridColumnViewModel : ViewModelBase
{
    public event ColumnResizedEvent ColumnResized;

    public void Resize(double newContainerWidth)
    {
        // some crazy custom sizing calculations -- don't ask...
        ResizeColumn(newWidth);
    }

    public void ResizeColumn(double width)
    {
        var handler = ColumnResized;
        if (handler != null)
            handler(width);
    }
}
然后是组装网格的代码:

public class CustomGrid
{
    public CustomGrid(GridViewModel viewModel)
    {
        // some stuff that parses control metadata out of the view model.
        // viewModel.Columns is a collection of GridColumnViewModels from above.
        foreach(var column in viewModel.Columns)
        {
            var gridCol = new DataGridTextColumn( ... );
            column.ColumnResized  += delegate(double width) { gridCol.Width = new DataGridLength(width); };
        }
    }
}
在应用程序中调整datagrid的大小时,将拾取resize事件,并在网格绑定到的viewmodel上调用resize方法。这将依次调用每个轴网柱视图模型的resize方法。然后,网格列视图模型引发
ColumnResized
事件,数据网格文本列订阅该事件,并更新其宽度


我意识到这并不能直接解决您的问题,但这是一种在没有依赖属性的情况下将视图模型“绑定”到数据网格列的方法。闭包是一个简单的构造,它很好地封装了我想要的行为,我身后的人也很容易理解它。我认为不难想象它如何被修改以适应能见度的变化。您甚至可以在页面/用户控件的加载事件中连接事件处理程序。

以下是我使用一些技巧提出的解决方案

首先,您需要从DataGrid继承

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;
        }
    }
}
公共类DataGridEx:DataGrid { 公共IEnumerable隐藏列 { get{return(IEnumerable)GetValue(HiddenColumnsProperty);} set{SetValue(HiddenColumnsProperty,value);} } 公共静态只读从属属性HiddenColumnsProperty= DependencyProperty.Register(“HiddenColumns”, 类型(IEnumerable), 类型(DataGridEx), 新的不动产数据(HiddenColumnsChanged)); 私有静态无效HiddenColumnsChanged(对象发送方, DependencyPropertyChangedEventArgs(参数) { var dg=发送方作为数据网格; if(dg==null | | args.NewValue==args.OldValue) 返回; var hiddenColumns=(IEnumerable)args.NewValue; foreach(dg.列中的var列) { if(hiddenColumns.Contains((string)column.GetValue(NameProperty))) column.Visibility=Visibility.collection; 其他的 column.Visibility=可见性.Visibility; } } } DataGridEx类根据DataGridColumn及其子体的x:Name添加了一个新的DP来隐藏列

要在XAML中使用:

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

Header=“计数”
Binding={Binding CountOfItems}”
您需要将它们添加到ViewModel或您使用的任何数据上下文中

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"};
}
私有IEnumerable\u隐藏列;
公共IEnumerable隐藏列
{
获取{return\u hiddenColumns;}
专用设备
{
如果(值==\u h
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"));
            }
        }
    }
}
var n = d as Notifier;
if (n != null)
{
     //Assign value in the callback will break the binding.
     //n.MyVisibility = (Visibility)e.NewValue;
     n.PropertyChanged(n, new PropertyChangedEventArgs("Visibility"));
}
public class ExtendedDataGridColumn : DataGridTemplateColumn
{
    public static readonly DependencyProperty VisibilityProperty = DependencyProperty.Register("Visibility", typeof(Visibility), typeof(DataGridTemplateColumn), new PropertyMetadata(Visibility.Visible, VisibilityChanged));
    public new Visibility Visibility
    {
        get { return (Visibility)GetValue(VisibilityProperty); }
        set { SetValue(VisibilityProperty, value); }
    }
    private static void VisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((DataGridTemplateColumn)d != null)
        {
            ((DataGridTemplateColumn)d).Visibility = (Visibility)e.NewValue;
        }
    }
}