我有一个BindingProxy将DataGrid的DataGridColumns的可视性-属性绑定到字典中的值(" ColumnsVisibility")。我也有一个上下文菜单,它应该可以隐藏/显示网格的列。
<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>
如果在InitializeComponent()之前用信息填充了字典" ColumnsVisibility",则将应用初始设置,即应用了我将DictionaryEntry设置为的值。
我的目标是选中上下文菜单中的复选框,然后列会出现/消失。因为ContextMenu和Columns不是与DataGrid或其他所有对象相同的可视树的成员,所以我使用的是Proxy。
我的问题是,在ContextMenu中选中/取消选中CheckBox不会更改ColumnsVisibility [ElementName]的值。如果将check / uncheck-Event添加到Checkbox,则可以在代码中使用它来更改它,但是触发PropertyChanged-Event不会改变任何视觉效果。该列保持原样。
indingProxy是否将事件转发到GUI,反之亦然?目前看来还没有。
任何人都有一个想法如何解决这个问题?
编辑:
BindingProxy:
public class BindingProxy : Freezable
{#region Overrides of Freezableprotected override Freezable CreateInstanceCore(){return new BindingProxy();}#endregionpublic 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));
}
编辑2:
ColumnsVisibilty属性
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"));}}
在InitializeComponent()之前,这是在加载时完成的:
1 | _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
{
/// <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);//(...)#endregionInitializeComponent();}#region Control triggeredprivate 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 worksif (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 Formpublic event PropertyChangedEventHandler PropertyChanged; #endregion
}//Binding Proxy
#region Freezable for Context-Menu-Data-Transmition
public class BindingProxy : Freezable
{#region Overrides of Freezableprotected override Freezable CreateInstanceCore(){return new BindingProxy();}#endregionpublic 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
}
<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>