BindingProxy:绑定到索引属性 [英] BindingProxy: binding to the indexed property

查看:234
本文介绍了BindingProxy:绑定到索引属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个BindingProxy绑定DataGridColumns的DataGridColumns属性到字典中的值(ColumnsVisibility)的Visibility属性。我也有一个上下文菜单,这应该可以隐藏/显示网格的列。

 < DataGrid Name =dgMachines
ItemsSource ={Binding HVMachineList,
UpdateSourceTrigger = PropertyChanged}
AutoGenerateColumns =False
>
< DataGrid.Resources>
< local:BindingProxy x:Key =proxyData ={Binding}/>
< ContextMenu x:Key =DataGridColumnHeaderContextMenu>
< MenuItem Header =Names>
< CheckBox Content =NameIsChecked ={Binding Data.ColumnsVisibility [ElementName],Source = {StaticResource proxy},UpdateSourceTrigger = PropertyChanged,Mode = TwoWay}/>
< / MenuItem>
< / ContextMenu>
< /DataGrid.Resources>
< DataGrid.Columns>
< DataGridTextColumn Header =NameBinding ={Binding ElementName}Visibility ={Binding Data.ColumnsVisibility [ElementName],UpdateSourceTrigger = PropertyChanged,Source = {StaticResource proxy},Converter = {StaticResource BoolToVisibilityConv} Mode = TwoWay}/>
< /DataGrid.Columns>
< / DataGrid>

初始加载起作用,如果DictionaryColumnsVisibility在InitializeComponent()之前填充了Information,则值我设置了DictionaryEntry,被应用。



我的目标是检查上下文菜单中的复选框,列出现/消失。因为ContextMenu和Columns不是DataGrid或其他所有视图树的成员,所以我使用Proxy。
我的问题是,ContextMenu中的CheckBox的检查/取消选中不会更改ColumnsVisibility [ElementName]的值。如果我将check / uncheck-Event添加到复选框,我可以通过在代码中使用它来更改它,但触发PropertyChanged-Event不会改变任何可视化。列保持原样。



BindingProxy是否将事件转发到GUI,反之亦然?目前看来似乎没有。
任何人都有一个想法如何解决这个问题?



编辑:
BindingProxy:

  public class BindingProxy:Freezable 
{
#region覆盖Freezable

保护覆盖Freezable CreateInstanceCore ()
{
return new BindingProxy();
}

#endregion

公共对象数据
{
get {return(object)GetValue(DataProperty); }
set {SetValue(DataProperty,value); }
}

//使用DependencyProperty作为Data的后备存储。这使得动画,样式,绑定等...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register(Data,typeof(object),typeof(BindingProxy),new UIPropertyMetadata(null)) ;
}

Edit2:
ColumnsVisibilty属性

 私人字典< string,bool> _ColumnsVisibility = new Dictionary< string,bool>(); 
public Dictionary< string,bool> ColumnsVisibility
{
get {return(_ColumnsVisibility);}
set
{
_ColumnsVisibility = value;

if(PropertyChanged!= null)
PropertyChanged(null,new PropertyChangedEventArgs(ColumnsVisibility));
}
}

在InitializeComponent()之前完成加载: / p>

  _ColumnsVisibility.Add(ElementName,false); 

Edit3
好​​的,这里是完整的源代码:
交互逻辑:

  using System.Collections.Generic; 
使用System.Security;
使用System.Windows;
使用System.Windows.Controls;
使用System.Collections.ObjectModel;
使用System.ComponentModel;

命名空间HyperV
{
///< summary>
/// HyperVControl.xaml的交互逻辑
///< / summary>
public partial class HyperVControl:UserControl,INotifyPropertyChanged
{
public HyperVControl()
{
#region设置列的默认可见性
_ColumnsVisibility.Add( ElementName,false);
//(...)
#endregion

InitializeComponent();
}

#region控制触发
private void UserControl_Loaded(object sender,RoutedEventArgs e)
{

}

///< summary>
///由复选框触发,位于DataGrid-Header的上下文菜单中,以显示/隐藏列
///< / summary>
///< param name =sender>发送此命令的复选框< / param>
///< param name =e>< / param>
private void CheckBox_Checked(object sender,RoutedEventArgs e)
{
//将ColumnsVisibility中的值设置为可以确定。该值不是通过绑定(但应该...)设置
ColumnsVisibility [((CheckBox)sender).Tag.ToString()] =(bool)((CheckBox)sender).IsChecked;

//没有任何工作
if(PropertyChanged!= null)
{
PropertyChanged(null,new PropertyChangedEventArgs(ColumnsVisibility));
PropertyChanged(null,new PropertyChangedEventArgs(ColumnsVisibility [Machinename]));
PropertyChanged(null,new PropertyChangedEventArgs(Data.ColumnsVisibility));
PropertyChanged(null,new PropertyChangedEventArgs(Data.ColumnsVisibility [Machinename]));
}
}
#endregion

#region属性(私有和公共)
private ObservableCollection< HyperVMachine> _HVMachineList;
私人字典< string,bool> _ColumnsVisibility = new Dictionary< string,bool>();

///< summary>
///包含有关虚拟客户端的所有加载信息
///< / summary>
public ObservableCollection< HyperVMachine> HVMachineList
{
get {return _HVMachineList; }
set
{
_HVMachineList = value;

if(PropertyChanged!= null)
PropertyChanged(this,new PropertyChangedEventArgs(HVMachineList));
}
}

///< summary>
///设置
///< / summary>
public Dictionary< string,bool> ColumnsVisibility
{
get {return(_ColumnsVisibility);}
set
{
_ColumnsVisibility = value;

if(PropertyChanged!= null)
PropertyChanged(null,new PropertyChangedEventArgs(ColumnsVisibility));
}
}
#endregion

#region事件
//更新窗体上的内容
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}

//绑定代理
#region可用于上下文菜单数据传输
public class BindingProxy:Freezable
{
#region覆盖Freezable

保护覆盖Freezable CreateInstanceCore()
{
返回新的BindingProxy();
}

#endregion

公共对象数据
{
get {return(object)GetValue(DataProperty); }
set {SetValue(DataProperty,value); }
}

//使用DependencyProperty作为Data的后备存储。这使得动画,样式,绑定等...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register(Data,typeof(object),typeof(BindingProxy),new UIPropertyMetadata(null)) ;
}
#endregion
}

XAML:

 < UserControl xmlns:Controls =clr-namespace:HyperV.Controls
x:Class =HyperV.HyperVControl
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
xmlns:mc =http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:d =http://schemas.microsoft.com/expression/blend/2008
xmlns:local =clr-namespace:HyperV
mc:Ignorable =d
d:DesignHeight =300d:DesignWidth =900
Loaded =UserControl_Loaded
DataContext ={Binding RelativeSource = {RelativeSource Mode = Self}}
>
< UserControl.Resources>
< ResourceDictionary>
< ResourceDictionary.MergedDictionaries>
< ResourceDictionary Source =Language / language.xaml/>
< ResourceDictionary Source =Language / language.de-DE.xaml/>
< /ResourceDictionary.MergedDictionaries>

< local:BoolToVisibilityConverter x:Key =BoolToVisibilityConv/>
< / ResourceDictionary>
< /UserControl.Resources>
< Grid>
< DataGrid Name =dgMachines
ItemsSource ={Binding HVMachineList,UpdateSourceTrigger = PropertyChanged}
AutoGenerateColumns =False
>
< DataGrid.Resources>
< local:BindingProxy x:Key =proxyData ={Binding}/>
< ContextMenu x:Key =DataGridColumnHeaderContextMenu>
< MenuItem Header ={StaticResource MenHeadGeneral}>
< CheckBox Tag =ElementNameContent ={StaticResource MenMachinename}IsChecked ={Binding Data.ColumnsVisibility [ElementName],Source = {StaticResource proxy},UpdateSourceTrigger = PropertyChanged,Mode = TwoWay}Checked = CheckBox_CheckedUnchecked =CheckBox_Checked/>
<! - ... - >
< / MenuItem>
<! - ... - >
< / ContextMenu>

< Style TargetType ={x:Type DataGridColumnHeader}>
< Setter Property =ContextMenuValue ={StaticResource DataGridColumnHeaderContextMenu}/>
< / Style>


< /DataGrid.Resources>
< DataGrid.Columns>
< DataGridTextColumn Header ={StaticResource MenMachinename}Binding ={Binding ElementName}Visibility ={Binding Data.ColumnsVisibility [ElementName],UpdateSourceTrigger = PropertyChanged,Source = {StaticResource proxy},Converter = {StaticResource BoolToVisibilityConv},Mode = TwoWay}/>
<! - ... - >
< /DataGrid.Columns>
< / DataGrid>
< / Grid>
< / UserControl>


解决方案

编辑: p>

这是一个错误:



PropertyChanged( null ,新的PropertyChangedEventArgs(ColumnsVisibility));



应该是:



PropertyChanged( ,新的PropertyChangedEventArgs(ColumnsVisibility ));



我已经盲目地将其复制到我的代码中的第一个编辑。嗯,有时候你只是看不到眼前的东西



对于将来,我建议您在某些基类中使用某种功能,如

  public class NotifyPropertyChangeableBase:INotifyPropertyChanged //通常我的名字有点像我的项目中的ViewModelBase,但是你的实际类是控件,所以它不是最合适的名称
{
protected void OnPropertyChanged(String propertyName)
{
if(this.PropertyChanged!= null)
this.PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}

public event PropertyChangedEventHandler PropertyChanged;
}

它没有解决问题,但至少有一个问题



编辑(我希望)最终解决方案:



看起来你无法通知WPF引擎您的字典已更改其项目。而标准字典不会自己做(它不实现ICollectionChanged甚至INotifyPropertyChanged)。



这就是为什么你必须使用自己的字典,或者是更精确的包装词典类:

  public class DictionaryNotificationWrapper< TKey,TValue> :IDictionary< TKey,TValue>,INotifyPropertyChanged 
{
#region Fields

private IDictionary< TKey,TValue> innerDictionary;

#endregion



#region构造函数

public DictionaryNotificationWrapper(IDictionary< TKey,TValue> innerDictionary)
{
if(innerDictionary == null)
throw new ArgumentNullException(innerDictionary,内部字典为null);

this.innerDictionary = innerDictionary;
}

#endregion



#region IDictionary执行

public TValue这个[TKey键]
{
get
{
return this.innerDictionary [key];
}
set
{
this.innerDictionary [key] = value;

this.OnPropertyChanged(Item []);
this.OnPropertyChanged(Count);
}
}

#endregion



#region未实现IDictionary成员 - 您可以自由完成工作

public void Add(TKey key,TValue value)
{
throw new NotImplementedException();
}

public bool ContainsKey(TKey key)
{
throw new NotImplementedException();
}

public ICollection< TKey>键
{
get {throw new NotImplementedException();
}

public bool Remove(TKey key)
{
throw new NotImplementedException();
}

public bool TryGetValue(TKey key,out TValue value)
{
throw new NotImplementedException();
}

public ICollection< TValue>值
{
get {throw new NotImplementedException();



public void Add(KeyValuePair< TKey,TValue> item)
{
throw new NotImplementedException();
}

public void Clear()
{
throw new NotImplementedException();
}

public bool包含(KeyValuePair< TKey,TValue>项目)
{
throw new NotImplementedException();
}

public void CopyTo(KeyValuePair< TKey,TValue> []数组,int arrayIndex)
{
throw new NotImplementedException();
}

public int Count
{
get {throw new NotImplementedException(); }
}

public bool IsReadOnly
{
get {throw new NotImplementedException();
}

public bool删除(KeyValuePair< TKey,TValue>项目)
{
throw new NotImplementedException();
}

public IEnumerator< KeyValuePair< TKey,TValue>> GetEnumerator()
{
throw new NotImplementedException();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}

#endregion



#region INotifyPropertyChanged实现


public event PropertyChangedEventHandler PropertyChanged;


protected void OnPropertyChanged(String propertyName)
{
if(this.PropertyChanged!= null)
this.PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}

#endregion
}

这样一个类:

  ///< summary> 
/// HyperVControl.xaml的交互逻辑
///< / summary>
public partial class HyperVControl:UserControl,INotifyPropertyChanged
{
#region构造函数

public HyperVControl()
{
//表单初始化
InitializeComponent();

//初始化列可见性集合
IDictionary< String,Boolean> innerColumnsVisibilityDictionary = new Dictionary< String,Boolean>();
innerColumnsVisibilityDictionary.Add(ElementName,true);
//包装可见性字典
this.ColumnsVisibility = new DictionaryNotificationWrapper< String,Boolean>(innerColumnsVisibilityDictionary);

//初始化网格的数据源
this.HVMachineList = new ObservableCollection< HyperVMachine>();
this.HVMachineList.Add(new HyperVMachine());
this.HVMachineList.Add(new HyperVMachine());
this.HVMachineList.Add(new HyperVMachine());
}

您将能够通知您的视觉组件而没有任何代码隐藏。 / p>

PS:我已经实现了INotifyProperyChanged来通知Item [] indexed属性的更改,但是您可以尝试实现INotifyCollectionChanged接口 - 我只是不确定它将如何工作索引绑定。

PPS:我没有看到你的评论,你发现 this.PropertyChanged( 这个 ,新... 问题。

PPPS:如果您有时间将问题标题更改为BindingProxy:绑定到索引属性,以更好地反映问题,只留下最后编辑的代码(避免重复) - 将其视为社区服务。


I have a BindingProxy to Bind the Visibility-Property of DataGridColumns of a DataGrid to a Value in a Dictionary ("ColumnsVisibility"). I Also have a Context-Menu, that should make it possible to hide/show the columns of the Grid.

<DataGrid Name="dgMachines"
          ItemsSource="{Binding HVMachineList,
          UpdateSourceTrigger=PropertyChanged}"                  
          AutoGenerateColumns="False"
          >
    <DataGrid.Resources>
        <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
        <ContextMenu x:Key="DataGridColumnHeaderContextMenu">
            <MenuItem Header="Names">
                <CheckBox Content="Name" IsChecked="{Binding Data.ColumnsVisibility[ElementName], Source={StaticResource proxy}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            </MenuItem>
        </ContextMenu>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding ElementName}" Visibility="{Binding Data.ColumnsVisibility[ElementName], UpdateSourceTrigger=PropertyChanged, Source={StaticResource proxy}, Converter={StaticResource BoolToVisibilityConv},  Mode=TwoWay}" />                
    </DataGrid.Columns>
</DataGrid>

The initial loading works, if the Dictionary "ColumnsVisibility" is filled with Information before InitializeComponent(), the value I set the DictionaryEntry to, is applied.

My target is to check the checkbox in the Contextmenu and the Column appears/disappears. Because the ContextMenu and the Columns are not Member of the same visual tree as the DataGrid or everything else, I'm using the Proxy. My problem is, that the checking/unchecking of the CheckBox in the ContextMenu don't change the value of ColumnsVisibility[ElementName]. If I add a check/uncheck-Event to the Checkbox, I can change it by using it in the code, but triggering a PropertyChanged-Event don't change anything visual. The column stays as it is.

Is the BindingProxy forwarding Events to the GUI and vice versa? Currently it seems like it doesn't. Anybody has an Idea how to solve this problem?

EDIT: The BindingProxy:

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));
}

Edit2: The ColumnsVisibilty Property

private Dictionary<string, bool> _ColumnsVisibility = new Dictionary<string, bool>();
public Dictionary<string, bool> ColumnsVisibility
    {
        get{return(_ColumnsVisibility);}
        set
        {   
            _ColumnsVisibility = value;

            if (PropertyChanged != null)
                PropertyChanged(null, new PropertyChangedEventArgs("ColumnsVisibility"));
        }
    }

Before InitializeComponent() this is done on loading:

_ColumnsVisibility.Add("ElementName", false);

Edit3 OK, here is the full sourcecode: Interaction logic:

using System.Collections.Generic;
using System.Security;
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace HyperV
{
/// <summary>
/// Interaction logic for HyperVControl.xaml
/// </summary>
public partial class HyperVControl : UserControl, INotifyPropertyChanged
{
    public HyperVControl()
    {            
        #region Set default visibility for Columns
        _ColumnsVisibility.Add("ElementName", false);
        //(...)
        #endregion

        InitializeComponent();
    }

    #region Control triggered
    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {

    }

    /// <summary>
    /// Is Triggered by Checkboxes, that are in the contextmenu of the DataGrid-Header to show/hide columns
    /// </summary>
    /// <param name="sender">The Checkbox, that send this command</param>
    /// <param name="e"></param>
    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        //This sets the value in ColumnsVisibility to be sure. The value is NOT set by binding (but should...)
        ColumnsVisibility[((CheckBox)sender).Tag.ToString()] = (bool)((CheckBox)sender).IsChecked;

        //Nothing of this works
        if (PropertyChanged != null)
        {
            PropertyChanged(null, new PropertyChangedEventArgs("ColumnsVisibility"));
            PropertyChanged(null, new PropertyChangedEventArgs("ColumnsVisibility[Machinename]"));
            PropertyChanged(null, new PropertyChangedEventArgs("Data.ColumnsVisibility"));
            PropertyChanged(null, new PropertyChangedEventArgs("Data.ColumnsVisibility[Machinename]"));
        }
    }
    #endregion

    #region Properties (private and publics)      
    private ObservableCollection<HyperVMachine> _HVMachineList;       
    private Dictionary<string, bool> _ColumnsVisibility = new Dictionary<string, bool>();

    /// <summary>
    /// Contains all loaded information about the virtual Clients
    /// </summary>
    public ObservableCollection<HyperVMachine> HVMachineList
    {
        get { return _HVMachineList; }
        set 
        {
            _HVMachineList = value;

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("HVMachineList"));
        }
    }

    /// <summary>
    /// To set 
    /// </summary>
    public Dictionary<string, bool> ColumnsVisibility
    {
        get{return(_ColumnsVisibility);}
        set
        {   
            _ColumnsVisibility = value;

            if (PropertyChanged != null)
                PropertyChanged(null, new PropertyChangedEventArgs("ColumnsVisibility"));
        }
    }
    #endregion

    #region Events
    //To Update Content on the Form
    public event PropertyChangedEventHandler PropertyChanged;        
    #endregion
}

//Binding Proxy
#region Freezable for Context-Menu-Data-Transmition
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));
}
#endregion
}

XAML:

<UserControl xmlns:Controls="clr-namespace:HyperV.Controls"  
         x:Class="HyperV.HyperVControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:HyperV"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="900"
         Loaded="UserControl_Loaded"
         DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"             
         >
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Language/language.xaml"/>
            <ResourceDictionary Source="Language/language.de-DE.xaml"/>
        </ResourceDictionary.MergedDictionaries>

        <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConv"/>
    </ResourceDictionary>
</UserControl.Resources>
<Grid>
    <DataGrid Name="dgMachines"
              ItemsSource="{Binding HVMachineList, UpdateSourceTrigger=PropertyChanged}"
              AutoGenerateColumns="False"                  
              >
        <DataGrid.Resources>
            <local:BindingProxy x:Key="proxy" Data="{Binding}"/>
            <ContextMenu x:Key="DataGridColumnHeaderContextMenu">
                <MenuItem Header="{StaticResource MenHeadGeneral}">
                    <CheckBox Tag="ElementName" Content="{StaticResource MenMachinename}" IsChecked="{Binding Data.ColumnsVisibility[ElementName], Source={StaticResource proxy}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"/>                        
                    <!-- ... -->
                </MenuItem>
                <!-- ... -->
            </ContextMenu>

            <Style TargetType="{x:Type DataGridColumnHeader}">
                <Setter Property="ContextMenu" Value="{StaticResource DataGridColumnHeaderContextMenu}" />
            </Style>


        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Header="{StaticResource MenMachinename}" Binding="{Binding ElementName}" Visibility="{Binding Data.ColumnsVisibility[ElementName], UpdateSourceTrigger=PropertyChanged, Source={StaticResource proxy}, Converter={StaticResource BoolToVisibilityConv},  Mode=TwoWay}" />                
            <!-- ... -->
        </DataGrid.Columns>
    </DataGrid>
</Grid>
</UserControl>

解决方案

EDIT:

It is an error for sure:

PropertyChanged(null, new PropertyChangedEventArgs("ColumnsVisibility"));

It should be:

PropertyChanged(this, new PropertyChangedEventArgs("ColumnsVisibility"));

I have blindly copied it into my first edit from your code. Well, sometimes you just don't see the things before your eyes

For future I recommend you to use some sort of a function in some base class like

public class NotifyPropertyChangeableBase: INotifyPropertyChanged // Usually I name it somewhat like 'ViewModelBase' in my projects, but your actual class is the control, so it is not the most appropriate name
{
    protected void OnPropertyChanged(String propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

It did not solve the issue, but it is at least one problem down

EDIT WITH(I HOPE) THE FINAL SOLUTION:

It looks that you cannot notify the WPF engine that your dictionary has changed its items. And standard Dictionary does not do it on its own(it does not implement the ICollectionChanged or even INotifyPropertyChanged).

That's why you have to use your own dictionary, or to be more precise wrapper dictionary class:

public class DictionaryNotificationWrapper<TKey, TValue> : IDictionary<TKey, TValue>, INotifyPropertyChanged
{
    #region Fields

    private IDictionary<TKey, TValue> innerDictionary;

    #endregion



    #region Constructors

    public DictionaryNotificationWrapper(IDictionary<TKey, TValue> innerDictionary)
    {
        if (innerDictionary == null)
            throw new ArgumentNullException("innerDictionary", "The inner dictionary is null");

        this.innerDictionary = innerDictionary;
    }

    #endregion



    #region IDictionary implementation

    public TValue this[TKey key]
    {
        get
        {
            return this.innerDictionary[key];
        }
        set
        {
            this.innerDictionary[key] = value;

            this.OnPropertyChanged("Item[]");
            this.OnPropertyChanged("Count");
        }
    }

    #endregion



    #region not implemented IDictionary members - you are free to finish the work

    public void Add(TKey key, TValue value)
    {
        throw new NotImplementedException();
    }

    public bool ContainsKey(TKey key)
    {
        throw new NotImplementedException();
    }

    public ICollection<TKey> Keys
    {
        get { throw new NotImplementedException(); }
    }

    public bool Remove(TKey key)
    {
        throw new NotImplementedException();
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        throw new NotImplementedException();
    }

    public ICollection<TValue> Values
    {
        get { throw new NotImplementedException(); }
    }


    public void Add(KeyValuePair<TKey, TValue> item)
    {
        throw new NotImplementedException();
    }

    public void Clear()
    {
        throw new NotImplementedException();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        throw new NotImplementedException();
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    public int Count
    {
        get { throw new NotImplementedException(); }
    }

    public bool IsReadOnly
    {
        get { throw new NotImplementedException(); }
    }

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        throw new NotImplementedException();
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion



    #region INotifyPropertyChanged implementation


    public event PropertyChangedEventHandler PropertyChanged;


    protected void OnPropertyChanged(String propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

With such a class:

/// <summary>
/// Interaction logic for HyperVControl.xaml
/// </summary>
public partial class HyperVControl : UserControl, INotifyPropertyChanged
{
    #region Constructors

    public HyperVControl()
    {
        // Form initialization
        InitializeComponent();

        // Initialize columns visibility collection
        IDictionary<String, Boolean> innerColumnsVisibilityDictionary = new Dictionary<String, Boolean>();
        innerColumnsVisibilityDictionary.Add("ElementName", true);
        // Wrap the visibility dictionary
        this.ColumnsVisibility = new DictionaryNotificationWrapper<String, Boolean>(innerColumnsVisibilityDictionary);

        // Initialize grid's datasource
        this.HVMachineList = new ObservableCollection<HyperVMachine>();
        this.HVMachineList.Add(new HyperVMachine());
        this.HVMachineList.Add(new HyperVMachine());
        this.HVMachineList.Add(new HyperVMachine());
    }

you will be able to notify your visual components without any code-behind.

P.S.: I have implemented INotifyProperyChanged that notifies about the changes in Item[] indexed property, but you could try to implement INotifyCollectionChanged interface - I am just unsure how it will work with indexed bindings.
P.P.S.: I haven't seen your comment that you have found this.PropertyChanged(this, new ... issue.
P.P.P.S.: If you have time then change the question title to "BindingProxy: binding to the indexed property" to better reflect the problem and leave only the code from the last edit(to avoid duplication) - think of it as the community service.

这篇关于BindingProxy:绑定到索引属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆