由字典支持的WPF可编辑DataGrid

时间:2015-01-24 14:02:39

标签: c# wpf dictionary datagrid

我有一个由Observable Dictionary集合支持的DataGrid。我想通过网格进行编辑,目前用户界面似乎不允许这样做。我还观察到,当将IEditableObject接口添加到Dictionary时,单击单元格时会调用接口方法,但UI本身没有任何反应。

这是我的最低范例:

    class MainWindowViewModel
    {
        public MainWindowViewModel() {
            ItemsSource = new ObservableCollection<DataGridData> {
                new DataGridData() {{"Name", "Abe"},{"Age", "50"},{"Gender", "Male"}},
                new DataGridData() {{"Name", "Shelly"},{"Age", "20"},{"Gender", "Female"}
                }
            };
        }

        public ObservableCollection<DataGridData> ItemsSource { get; set; }
    }

    public class DataGridData : Dictionary<string, string>, IEditableObject {
        public void BeginEdit(){}

        public void CancelEdit(){}

        public void EndEdit(){}
    }

    public partial class MainWindow {
        public MainWindow() {
            DataContext = new MainWindowViewModel();

            InitializeComponent();
            foreach (var col in ViewModel.ItemsSource[0].Keys) {
                AddColumns(col, col);
            }

        }

        MainWindowViewModel ViewModel {
            get { return DataContext as MainWindowViewModel; }
        }

        void AddColumns(string id, string name)
        {
            FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock));

            textBlock.SetValue(TextBlock.PaddingProperty, new Thickness(2));
            textBlock.SetValue(TextBlock.TextProperty, new Binding(string.Format("[{0}]", id)));

            Binding textDecorationBinding = new Binding();
            textDecorationBinding.ElementName = "DataGrid";
            textDecorationBinding.Path = new PropertyPath("DataContext.TextDecoration");

            textBlock.SetValue(TextBlock.TextDecorationsProperty, textDecorationBinding);

            DataTemplate cellTemplate = new DataTemplate();
            cellTemplate.VisualTree = textBlock;

            DataGridTemplateColumn column = new DataGridTemplateColumn();
            column.Header = name;
            column.SortMemberPath = name;
            column.CellTemplate = cellTemplate;

            DataGrid.Columns.Add(column);
        }
    }

<Window x:Class="Datagrid.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" mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid 
            Name="DataGrid"
            ItemsSource="{Binding ItemsSource}"
            AutoGenerateColumns="False"
            >
        </DataGrid>
    </Grid>
</Window>

使用字典是因为我在编译时没有关于列数据的任何内容。上面的ItemsSource只是一个例子,但我可以在运行时拥有任意数量的键/值。

启用编辑单元格数据需要进行哪些更改?

修改 我从未使用它,但我正在阅读使用反射来发出可以替换字典键/值的实际类。除非有人提出相反的建议,否则我可以试一试。

1 个答案:

答案 0 :(得分:0)

在我的选择中,你的代码有点曲折&#34;。实际上,我不会使用Dictionary作为我想要处理的对象的模型。在我看来,最好使用专门的类(这样你就可以实现&#34;着名的&#34; INotifyPropertyChanged接口)。 例如,您可以使用Person类(这里是一个非常快速的实现):

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Genders Gender { get; set; }
}

您可以实施IEditableObject,但这不是强制性的。

最后(但并非最不重要)如果我是你,我会在我的XAML中声明DataGrid列而不是我的代码(我无法在你的情况下看到使用代码的正当理由;我不会&#39 ; t知道你可能需要动态列。在这种情况下,你可以阅读这个非常好的article)。

所以我的ViewModel是(您可以轻松地将Dictionary替换为Person类):

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        People = new ObservableCollection<Dictionary<string, string>> {
            new Dictionary<string, string>() {{"Name", "Abe"}, {"Age", "50"}, {"Gender", "Male"}},
            new Dictionary<string, string>() {{"Name", "Shelly"}, {"Age", "20"}, {"Gender", "Female"}}
        };
    }
    public ObservableCollection<Dictionary<string, string>> People { get; private set; } 
}

我的XAML(如果您使用Person替换Dictionary,请从列出价中删除方括号):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">

    <StackPanel Orientation="Vertical">
        <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=People}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Path=[Name]}" Header="Name" Width="2*" />
                <DataGridTextColumn Binding="{Binding Path=[Age]}" Header="Age" Width="*" />
                <DataGridTextColumn Binding="{Binding Path=[Gender]}" Header="Gender" Width="*" />
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</Window>

我的窗口代码隐藏:

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }
    }
}

通过这种方式,一切正常,您可以使用DataGrid编辑数据。 我希望这个样本可以帮到你。

修改

如果您需要使用自己的方法,可能需要使用AddColumns方法来宣告CellEditingTemplate。你的方法将成为:

private void AddColumns(string id, string name)
{
    FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock));

    textBlock.SetValue(TextBlock.PaddingProperty, new Thickness(2));
    textBlock.SetValue(TextBlock.TextProperty, new Binding(String.Format("[{0}]", id)));

    FrameworkElementFactory textBox = new FrameworkElementFactory(typeof(TextBox));

    textBox.SetValue(TextBox.PaddingProperty, new Thickness(2));
    textBox.SetValue(TextBox.TextProperty, new Binding(String.Format("[{0}]", id)));

    Binding textDecorationBinding = new Binding();
    textDecorationBinding.ElementName = "DataGrid";
    textDecorationBinding.Path = new PropertyPath("DataContext.TextDecoration");

    textBlock.SetValue(TextBlock.TextDecorationsProperty, textDecorationBinding);

    DataTemplate cellTemplate = new DataTemplate();
    cellTemplate.VisualTree = textBlock;

    DataTemplate cellEditingTemplate = new DataTemplate();
    cellEditingTemplate.VisualTree = textBox;

    DataGridTemplateColumn column = new DataGridTemplateColumn();
    column.Header = name;
    column.SortMemberPath = name;
    column.CellTemplate = cellTemplate;
    column.CellEditingTemplate = cellEditingTemplate;

    DataGrid.Columns.Add(column);
}

我读到你正在考虑使用反射来发出一个可以替换字典键/值的实际类。当然这是一个解决方案,但我建议考虑ICustomTypeDescriptorCustomTypeDescriptor