BindingProxy:绑定到索引属性

我有一个BindingProxy将DataGrid的DataGridColumns的Visibility属性绑定到Dictionary中的值(“ColumnsVisibility”)。 我还有一个Context-Menu,可以隐藏/显示Grid的列。

             

初始加载工作,如果字典“ColumnsVisibility”在InitializeComponent()之前填充了Information,则应用我设置DictionaryEntry的值。

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

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

编辑: 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: ColumnsVisibilty属性

 private Dictionary _ColumnsVisibility = new Dictionary(); public Dictionary ColumnsVisibility { get{return(_ColumnsVisibility);} set { _ColumnsVisibility = value; if (PropertyChanged != null) PropertyChanged(null, new PropertyChangedEventArgs("ColumnsVisibility")); } } 

在InitializeComponent()之前,这是在加载时完成的:

 _ColumnsVisibility.Add("ElementName", false); 

编辑3好了,这是完整的源代码:交互逻辑:

 using System.Collections.Generic; using System.Security; using System.Windows; using System.Windows.Controls; using System.Collections.ObjectModel; using System.ComponentModel; namespace HyperV { ///  /// Interaction logic for HyperVControl.xaml ///  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) { } ///  /// Is Triggered by Checkboxes, that are in the contextmenu of the DataGrid-Header to show/hide columns ///  /// The Checkbox, that send this command ///  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 _HVMachineList; private Dictionary _ColumnsVisibility = new Dictionary(); ///  /// Contains all loaded information about the virtual Clients ///  public ObservableCollection HVMachineList { get { return _HVMachineList; } set { _HVMachineList = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("HVMachineList")); } } ///  /// To set ///  public Dictionary 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:

                                 

编辑:

这肯定是一个错误:

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

它应该是:

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

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

为了将来,我建议你在某些基类中使用某种函数

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

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

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

看起来您无法通知WPF引擎您的字典已更改其项目。 标准字典本身不会这样做(它没有实现ICollectionChanged甚至INotifyPropertyChanged)。

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

 public class DictionaryNotificationWrapper : IDictionary, INotifyPropertyChanged { #region Fields private IDictionary innerDictionary; #endregion #region Constructors public DictionaryNotificationWrapper(IDictionary 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 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 Values { get { throw new NotImplementedException(); } } public void Add(KeyValuePair item) { throw new NotImplementedException(); } public void Clear() { throw new NotImplementedException(); } public bool Contains(KeyValuePair item) { throw new NotImplementedException(); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { throw new NotImplementedException(); } public int Count { get { throw new NotImplementedException(); } } public bool IsReadOnly { get { throw new NotImplementedException(); } } public bool Remove(KeyValuePair item) { throw new NotImplementedException(); } public IEnumerator> 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 } 

有了这样一堂课:

 ///  /// Interaction logic for HyperVControl.xaml ///  public partial class HyperVControl : UserControl, INotifyPropertyChanged { #region Constructors public HyperVControl() { // Form initialization InitializeComponent(); // Initialize columns visibility collection IDictionary innerColumnsVisibilityDictionary = new Dictionary(); innerColumnsVisibilityDictionary.Add("ElementName", true); // Wrap the visibility dictionary this.ColumnsVisibility = new DictionaryNotificationWrapper(innerColumnsVisibilityDictionary); // Initialize grid's datasource this.HVMachineList = new ObservableCollection(); this.HVMachineList.Add(new HyperVMachine()); this.HVMachineList.Add(new HyperVMachine()); this.HVMachineList.Add(new HyperVMachine()); } 

您将能够在没有任何代码隐藏的情况下通知您的可视组件。

PS:我已经实现了INotifyProperyChanged,它通知了Item []索引属性的变化,但你可以尝试实现INotifyCollectionChanged接口 – 我只是不确定它如何与索引绑定一起工作。
PPS:我没有看到你的评论,你发现了这个 this.PropertyChanged( 这个 , new ...问题。
PPPS:如果您有时间,请将问题标题更改为“BindingProxy:绑定到索引属性”以更好地反映问题,并仅保留上次编辑的代码(以避免重复) – 将其视为社区服务。