绑定到WPF DataGrid的DataTable不会更新

时间:2016-11-24 00:22:56

标签: c# wpf mvvm datatable datagrid

我有一个绑定到DataTable的WPF DataGrid。我不喜欢这样做,但数据来自一个分隔的文本文件,我不知道该表将包含多少字段(列)。编程这似乎是最简单的方法来实现这一点(使用MVVM并避免代码隐藏),但考虑到我想要双向绑定,也许这不起作用。

DataGrid在视图中定义如下:

        <DataGrid x:Name="dataGrid" ItemsSource="{Binding FileTable, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
              HorizontalAlignment="Stretch" Margin="0,60,0,0" VerticalAlignment="Stretch">
    </DataGrid>

ViewModel通过读取文本文件来设置数据表,并在每行的末尾添加两个布尔值。我希望布尔值映射到DataGrid中的复选框,但它们不会,并且当值发生更改时,我不会在viewmodel中获取任何事件。我想我需要更改其他相关问题中看到的数据表,但它们都响应视图模型更改视图(如添加列的按钮),而不是更改来自数据网格内的数据网格图。

对于上下文,这里是我的ViewModel中的FileTable成员:

private DataTable _fileTable;
public DataTable FileTable
{
    get
    {
        return _fileTable;
    }
    set
    {
        if (value != _fileTable)
        {
            _fileTable = value;
            NotifyPropertyChanged("FileTable");
        }
    }
}

以下是从文本文件创建数据表的代码:

public DataTable ParseFileToTable(Document doc, string PlaceHolders)
{
    if (dt == null)
    {
        dt = new DataTable();
    }
    else dt.Clear();

    if (filepath == null) 
    {
        OpenFileDialog dlg = new OpenFileDialog();
        dlg.DefaultExt = ".txt"; // Default file extension
        dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

        Nullable<bool> result = dlg.ShowDialog();
        if (result != true) return null;

        filepath = dlg.FileName;
        StreamReader r = new StreamReader(filepath);
        string line = r.ReadLine(); // First Line is Column Names
        string[] h_line = line.Split('\t'); // tab delimeter is hardcoded for now
        for(int i = 0; i < h_line.Count(); i++) 
        {
            dt.Columns.Add(h_line[i]);
        }
        dt.Columns.Add(new DataColumn("Exists", typeof(bool)));
        dt.Columns.Add(new DataColumn("Placeholder", typeof(bool)));


        //read the rest of the file
        while (!r.EndOfStream)
        {
            line = r.ReadLine();
            string [] a_line = line.Split('\t');
            DataRow nRow = dt.NewRow();
            for(int i = 0; i < h_line.Count(); i++)
            {
                nRow[h_line[i]] = a_line[i];
            }
            nRow["Exists"] = DoesSheetExist(doc, h_line[0], a_line[0]);
            nRow["Placeholder"] = IsAPlaceholder(a_line[0], PlaceHolders);
            dt.Rows.Add(nRow);
        }
    }
    return dt;
}

1 个答案:

答案 0 :(得分:0)

您需要使用行为

动态创建 DatagridColumns
    /// <summary>
    /// Creating dymanic columns to the datagrid
    /// </summary>
    public class ColumnsBindingBehaviour : Behavior<DataGrid>
    {
        public ObservableCollection<DataGridColumn> Columns
        {
            get { return (ObservableCollection<DataGridColumn>)base.GetValue(ColumnsProperty); }
            set { base.SetValue(ColumnsProperty, value); }
        }
        public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register("Columns",
            typeof(ObservableCollection<DataGridColumn>), typeof(ColumnsBindingBehaviour),
                new PropertyMetadata(OnDataGridColumnsPropertyChanged));
        private static void OnDataGridColumnsPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            var context = source as ColumnsBindingBehaviour;
            var oldItems = e.OldValue as ObservableCollection<DataGridColumn>;
            if (oldItems != null)
            {
                foreach (var one in oldItems)
                    context._datagridColumns.Remove(one);
                oldItems.CollectionChanged -= context.collectionChanged;
            }
            var newItems = e.NewValue as ObservableCollection<DataGridColumn>;
            if (newItems != null)
            {
                foreach (var one in newItems)
                    context._datagridColumns.Add(one);
                newItems.CollectionChanged += context.collectionChanged;
            }
        }
        private ObservableCollection<DataGridColumn> _datagridColumns = new ObservableCollection<DataGridColumn>();
        protected override void OnAttached()
        {
            base.OnAttached();
            this._datagridColumns = AssociatedObject.Columns;
        }
        private void collectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewItems != null)
                        foreach (DataGridColumn one in e.NewItems)
                            _datagridColumns.Add(one);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (e.OldItems != null)
                        foreach (DataGridColumn one in e.OldItems)
                            _datagridColumns.Remove(one);
                    break;
                case NotifyCollectionChangedAction.Move:
                    _datagridColumns.Move(e.OldStartingIndex, e.NewStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    _datagridColumns.Clear();
                    if (e.NewItems != null)
                        foreach (DataGridColumn one in e.NewItems)
                            _datagridColumns.Add(one);
                    break;
            }
        }
    }

ViewModel属性如下

        //Datagrid Column collection in Viewmodel
        private ObservableCollection<DataGridColumn> dataGridColumns;
        public ObservableCollection<DataGridColumn> DataGridColumns
        {
            get
            {
                return dataGridColumns;
            }
            set
            {
                dataGridColumns = value;
                OnPropertyChanged();
            }
        }

创建数据表,按如下方式绑定到它,

    //Getting column names from datatable
    string[] columnNames = (from dc in dt.Columns.Cast<DataColumn>() select dc.ColumnName).ToArray();

    //Add two of your columns
    dt.Columns.Add(new DataColumn("Exists", typeof(bool)));
    dt.Columns.Add(new DataColumn("Placeholder", typeof(bool)));


    //Create DataGrid Column and bind datatable fields
    foreach (string item in columnNames)
    {
                        if (item.Equals("your Normal Column"))
                        {
                            DataGridColumns.Add(new DataGridTextColumn() { Header = "Normal Column", Binding = new Binding("Normal Column Name"), Visibility = Visibility.Visible});
                        }

                        else if (!item.Contains("your Bool column"))
                        {
                            //Creating checkbox control 

                          FrameworkElementFactory checkBox = new FrameworkElementFactory(typeof(CheckBox));
                         checkBox.SetValue(CheckBox.HorizontalAlignmentProperty, HorizontalAlignment.Center);

                            checkBox.Name = "Dynamic name of your check box";
                            //Creating binding
                            Binding PermissionID = new Binding(item); 

                            PermissionID.Mode = BindingMode.TwoWay;

                            PermissionID.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;


                            checkBox.SetBinding(CheckBox.TagProperty, BindingVal);

                            DataTemplate d = new DataTemplate();
                            d.VisualTree = checkBox;
                            DataGridTemplateColumn dgTemplate = new DataGridTemplateColumn();
                            dgTemplate.Header = item;
                            dgTemplate.CellTemplate = d;
                            DataGridColumns.Add(dgTemplate);
                        }

                    }

最后 Xaml中的命名空间

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:vm="clr-namespace:YourProject.ViewModels"
<DataGrid  AutoGenerateColumns="False"
                      ItemsSource="{Binding Datatable,
 UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,IsAsync=True}">
                <i:Interaction.Behaviors>
                    <vm:ColumnsBindingBehaviour Columns="{Binding DataContext.DataGridColumns, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                </i:Interaction.Behaviors>
            </DataGrid>