繁体   English   中英

绑定到WPF DataGrid的DataTable不会更新

[英]DataTable bound to WPF DataGrid does not update

我有绑定到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(例如添加列的按钮),而不是使更改来自于内部的datagrid。视图。

对于上下文,这是我的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;
}

您需要使用行为动态创建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>

虽然我尽量避免使用代码,但我认为我在此解决方案中的使用是可以接受的,因为视图只是准备显示具有动态大小(或形状)的ViewModel。

我没有读取DataTable,而是读取了一个包含字符串列表和两个布尔值的对象。 在我的ViewModel中,我有一个可观察到的对象集合。 像这样在后面的代码中初始化datagrid(只是显示的字符串列表,两个复选框列不需要循环):

    public MainWindow(FileParametersViewModel vm)
    {
        InitializeComponent();
        DataContext = vm;
        dataGrid.ItemsSource = vm.lParams;
        for (int i = 0; i < vm.ParamNames.Count(); i++)
        {
            DataGridTextColumn col = new DataGridTextColumn();
            col.Header = vm.ParamNames[i];
            string path = String.Format("pArray[{0}]", i);
            col.Binding = new Binding(path);
            dataGrid.Columns.Add(col);
        }
    }

和我的收藏对象:

public class FileSheetParameters
{
    public FileSheetParameters()
    {
        SheetExists = false;
        IsPlaceholder = false;
        pArray = new List<string>();
    }

    public bool SheetExists { get; set; }
    public bool IsPlaceholder { get; set; }
    public List<string> pArray { get; set; }
}

在我看来,这是最简单的方法。 我尚未对其进行全面测试,但到目前为止它似乎可以正常工作。 如果发现其他问题将更新。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM