【发布时间】:2014-08-18 14:09:14
【问题描述】:
我有一个 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>
初始加载有效,如果 Dictionary“ColumnsVisibility”在 InitializeComponent() 之前填充了信息,则应用我设置 DictionaryEntry 的值。
我的目标是选中上下文菜单中的复选框,然后列出现/消失。因为 ContextMenu 和 Columns 与 DataGrid 或其他所有内容都不是同一可视树的成员,所以我使用的是代理。 我的问题是,在 ContextMenu 中选中/取消选中 CheckBox 不会更改 ColumnsVisibility [ElementName] 的值。如果我向复选框添加一个选中/取消选中事件,我可以通过在代码中使用它来更改它,但触发 PropertyChanged-Event 不会改变任何视觉效果。该列保持原样。
BindingProxy 是否将事件转发到 GUI,反之亦然?目前好像没有。 有人知道如何解决这个问题吗?
编辑: 绑定代理:
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));
}
编辑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() 之前,这是在加载时完成的:
_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);
//(...)
#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>
【问题讨论】:
-
能否展示绑定到BindingProxy的数据模型?
-
嗨,尤金,我把它添加到原始帖子中
-
我的意思是你窗口的数据源:local:BindingProxy x:Key="proxy" Data="{Binding}"
-
您是否尝试过在可视化树中创建复选框(通过 BindingProxy 绑定)?只是看看这个问题是否与ContextMenu有关。
-
您好,没有特殊的数据源。它绑定到父级。所以我可以通过 Data.whatever 访问所有内容(在本例中为 Data.ColumnsVisibility)。我在原始帖子中添加了 ColumnsVisibility。如果我更改值,即使用按钮并触发 PropertyChanged,则网格不会对此做出反应
标签: c# wpf datagrid propertychanged