我正在使用WPF中的DataGrid,我遇到列可见性问题。我将ItemSource分配给一个ObservableCollection,并且所有绑定都在XAML中正确设置,一切正常。为了方便用户,我需要能够在UI上显示和隐藏列。我已经在C#文件中设置了列可见性的绑定,这些绑定可以正常显示和隐藏大多数列。但是,包含ComboBoxes的DataGridTemplateColumns重新显示为空。绑定仍然正确设置,因为只要数据发生更改,它就会被正确推送到UI并再次可见。我还验证了当列被设置为隐藏时,基础数据没有被清除。
这是我隐藏然后使用ComboBox显示列时得到的结果:Missing ComboBox Data
完整示例代码如下:
XAML:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="DeviceDataGrid" Margin="10,50,10,10" AutoGenerateColumns="False" CanUserReorderColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Model Name" IsReadOnly="true" Binding="{Binding ModelName}" Width="Auto">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="5,0"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Header="IGMP" IsReadOnly="False" Width="Auto" SortMemberPath="IgmpVersion">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Margin="4" IsEnabled="True" ItemsSource="{Binding IgmpVersionValues}" SelectedItem="{Binding IgmpVersion}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Menu Height="25" VerticalAlignment="Top">
<MenuItem Header="View" Height="25">
<MenuItem x:Name="MenuViewModelName" Header="Model Name" HorizontalAlignment="Left" Width="175" IsCheckable="True" StaysOpenOnClick="True"/>
<MenuItem x:Name="MenuViewIgmp" Header="IGMP" HorizontalAlignment="Left" Width="175" IsCheckable="True" StaysOpenOnClick="True"/>
</MenuItem>
</Menu>
</Grid>
C#:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Test
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<ExtendedDevice> MyDevices = new ObservableCollection<ExtendedDevice>();
GlobalVars GV = new GlobalVars();
public MainWindow()
{
InitializeComponent();
DeviceDataGrid.ItemsSource = MyDevices;
MyDevices.Add(new ExtendedDevice() { ModelName = "Model A", IgmpVersion = eExtendedIgmpVersion.V2 });
MyDevices.Add(new ExtendedDevice() { ModelName = "Model B", IgmpVersion = eExtendedIgmpVersion.V3 });
MyDevices.Add(new ExtendedDevice() { ModelName = "Model C", IgmpVersion = eExtendedIgmpVersion.Unknown });
BindingOperations.SetBinding(this.DeviceDataGrid.Columns[0], DataGridColumn.VisibilityProperty, BindingHelper.CreateOneWayBindingWithConverter(GV, "ShowColumnModelName", new BooleanToVisibleConverter(), null));
BindingOperations.SetBinding(this.MenuViewModelName, MenuItem.IsCheckedProperty, BindingHelper.CreateTwoWayBinding(GV, "ShowColumnModelName"));
BindingOperations.SetBinding(this.DeviceDataGrid.Columns[1], DataGridColumn.VisibilityProperty, BindingHelper.CreateOneWayBindingWithConverter(GV, "ShowColumnIgmp", new BooleanToVisibleConverter(), null));
BindingOperations.SetBinding(this.MenuViewIgmp, MenuItem.IsCheckedProperty, BindingHelper.CreateTwoWayBinding(GV, "ShowColumnIgmp"));
}
}
public enum eExtendedIgmpVersion : int
{
V3 = 3,
V2 = 2,
Unknown = -1,
}
public class ExtendedDevice : DiscoveredDevice
{
private eExtendedIgmpVersion _IgmpVersion = eExtendedIgmpVersion.Unknown;
public eExtendedIgmpVersion IgmpVersion
{
get { return _IgmpVersion; }
set { _IgmpVersion = value; RaisePropertyChanged(); }
}
public IEnumerable<eExtendedIgmpVersion> IgmpVersionValues
{
get
{
return Enum.GetValues(typeof(eExtendedIgmpVersion)).Cast<eExtendedIgmpVersion>();
}
}
public ExtendedDevice() : base() { }
}
public class DiscoveredDevice : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _ModelName;
public string ModelName
{
get { return _ModelName; }
set { _ModelName = value; RaisePropertyChanged(); }
}
protected virtual void RaisePropertyChanged([CallerMemberName] string PropertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public DiscoveredDevice()
{
}
}
static class BindingHelper
{
public static Binding CreateTwoWayBinding(Object Source, String Path)
{
Binding myBinding = new Binding();
myBinding.Source = Source;
myBinding.Path = new PropertyPath(Path);
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
return myBinding;
}
public static Binding CreateOneWayBindingWithConverter(Object Source, String Path, IValueConverter Converter, Object ConverterParameter)
{
Binding myBinding = new Binding();
myBinding.Source = Source;
myBinding.Path = new PropertyPath(Path);
myBinding.Mode = BindingMode.OneWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myBinding.Converter = Converter;
myBinding.ConverterParameter = ConverterParameter;
return myBinding;
}
}
public class GlobalVars : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _ShowColumnModelName = true;
public bool ShowColumnModelName
{
get { return _ShowColumnModelName; }
set { _ShowColumnModelName = value; RaisePropertyChanged(); }
}
private bool _ShowColumnIgmp = true;
public bool ShowColumnIgmp
{
get { return _ShowColumnIgmp; }
set { _ShowColumnIgmp = value; RaisePropertyChanged(); }
}
protected virtual void RaisePropertyChanged([CallerMemberName] string PropertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
}
public class BooleanToVisibleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool? input = value as bool?;
return input == true ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
}