WPF DataGrid列可见性问题

时间:2017-12-12 19:02:09

标签: c# wpf xaml datagrid

我正在使用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();
        }
    }
}

0 个答案:

没有答案