C# WPF MVVM动态列多线程

C# WPF MVVM动态列多线程,c#,wpf,mvvm,datagrid,dynamic-columns,C#,Wpf,Mvvm,Datagrid,Dynamic Columns,我目前正在开发一个C#System.Windows.Controls.DataGrid,它需要根据数据动态生成列。它可以在运行时添加和/或删除列 我在ViewModel类中使用一个线程来更新提供给DataGrid的ObservableCollection 我读过这本书,它解释了我为我的问题找到的最佳解决方案。尽管如此,DataGridExtension类中的Columns.CollectionChanged委托引发InvalideOperationException:调用线程无法访问此对象,因为

我目前正在开发一个C#System.Windows.Controls.DataGrid,它需要根据数据动态生成列。它可以在运行时添加和/或删除列

我在ViewModel类中使用一个线程来更新提供给DataGrid的ObservableCollection

我读过这本书,它解释了我为我的问题找到的最佳解决方案。尽管如此,DataGridExtension类中的Columns.CollectionChanged委托引发InvalideOperationException:调用线程无法访问此对象,因为其他线程拥有它

这里有一些代码来描述这一切:
视图XAML

<DataGrid ItemsSource="{Binding CollectionView, Source={StaticResource ViewModel}}" local:DataGridExtension.Columns="{Binding DataGridColumns, Source={StaticResource ViewModel}}" AutoGenerateColumns="False" Name="dataGrid">
public static class DataGridExtension
{
  public static Dispatcher _currentDispatcher;

  public static readonly DependencyProperty ColumnsProperty =
    DependencyProperty.RegisterAttached("Columns",
    typeof(ObservableCollection<DataGridColumn>),
    typeof(DataGridExtension),
    new UIPropertyMetadata(new ObservableCollection<DataGridColumn>(), OnDataGridColumnsPropertyChanged));

  private static void OnDataGridColumnsPropertyChanged(DependencyObject iObj, DependencyPropertyChangedEventArgs iArgs)
  {
    if (iObj.GetType() == typeof(DataGrid))
    {
     DataGrid myGrid = iObj as DataGrid;

      ObservableCollection<DataGridColumn> Columns = (ObservableCollection<DataGridColumn>)iArgs.NewValue;

      if (Columns != null)
      {
        myGrid.Columns.Clear();

        if (Columns != null && Columns.Count > 0)
        {
          foreach (DataGridColumn dataGridColumn in Columns)
          {
            myGrid.Columns.Add(dataGridColumn);
          }
        }


        Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args)
        {
          if (args.NewItems != null)
          {
            UserControl control = ((UserControl)((Grid)myGrid.Parent).Parent);
            foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>())
            {
              /// This is where I tried to fix the exception. ///
              DataGridColumn temp = new DataGridTextColumn();
              temp.Header = column.Header;
              temp.SortMemberPath = column.SortMemberPath;
              control.Dispatcher.Invoke(new Action(delegate()
                {
                  myGrid.Columns.Add(temp);
                }), DispatcherPriority.Normal);
              ////////////////////////////////////////////////////
            }
          }

          if (args.OldItems != null)
          {
            foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>())
            {
              myGrid.Columns.Remove(column);
            }
          }
        };
      }
    }
  }

  public static ObservableCollection<DataGridColumn> GetColumns(DependencyObject iObj)
  {
    return (ObservableCollection<DataGridColumn>)iObj.GetValue(ColumnsProperty);
  }

  public static void SetColumns(DependencyObject iObj, ObservableCollection<DataGridColumn> iColumns)
  {
    iObj.SetValue(ColumnsProperty, iColumns);
  }
}
UserControl control = ((UserControl)((Grid)myGrid.Parent).Parent);
Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args)
        {
          control.Dispatcher.Invoke(new Action(delegate()
          {
            if (args.NewItems != null)
            {
              foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>())
              {
                DataGridColumn temp = new DataGridTextColumn();
                temp.Header = column.Header;
                temp.SortMemberPath = column.SortMemberPath;
                myGrid.Columns.Add(temp);
              }
            }

            if (args.OldItems != null)
            {
              foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>())
              {
                myGrid.Columns.Remove(column);
              }
            }
          }), DispatcherPriority.Normal);
        };

视图模型类

public ObservableCollection<DataGridColumn> DataGridColumns
{
  get { return columns; }
  set { columns = value; }
}
private void getViewData()
{
  while (true)
  {
    Thread.Sleep(1000);

    foreach (DataObject data in dataObjects)
    {
        int index = -1;
        foreach (DataGridColumn c in columns)
        {
          if (c.Header.Equals(column.Header))
            index = columns.IndexOf(c);
        }

        DataGridColumn column = new DataGridTextColumn();
        ... Creating the column based on data from DataObject ...
        DataGridExtension._currentDispatcher = Dispatcher.CurrentDispatcher;
        if (index == -1)
        {
          this.columns.Add(column);
        }
        else
        {
          this.columns.RemoveAt(index);
          this.columns.Add(column);
        }
    }
  }
}
公共ObservableCollection DataGridColumns
{
获取{返回列;}
设置{columns=value;}
}
私有void getViewData()
{
while(true)
{
睡眠(1000);
foreach(数据对象中的数据对象数据)
{
int指数=-1;
foreach(列中的DataGridC列)
{
if(c.标题等于(列标题))
索引=列。IndexOf(c);
}
DataGridColumn=新DataGridTextColumn();
…根据来自DataObject的数据创建列。。。
DataGridExtension.\u currentDispatcher=Dispatcher.currentDispatcher;
如果(索引==-1)
{
this.columns.Add(column);
}
其他的
{
this.columns.RemoveAt(索引);
this.columns.Add(column);
}
}
}
}
DataGridExtension类

<DataGrid ItemsSource="{Binding CollectionView, Source={StaticResource ViewModel}}" local:DataGridExtension.Columns="{Binding DataGridColumns, Source={StaticResource ViewModel}}" AutoGenerateColumns="False" Name="dataGrid">
public static class DataGridExtension
{
  public static Dispatcher _currentDispatcher;

  public static readonly DependencyProperty ColumnsProperty =
    DependencyProperty.RegisterAttached("Columns",
    typeof(ObservableCollection<DataGridColumn>),
    typeof(DataGridExtension),
    new UIPropertyMetadata(new ObservableCollection<DataGridColumn>(), OnDataGridColumnsPropertyChanged));

  private static void OnDataGridColumnsPropertyChanged(DependencyObject iObj, DependencyPropertyChangedEventArgs iArgs)
  {
    if (iObj.GetType() == typeof(DataGrid))
    {
     DataGrid myGrid = iObj as DataGrid;

      ObservableCollection<DataGridColumn> Columns = (ObservableCollection<DataGridColumn>)iArgs.NewValue;

      if (Columns != null)
      {
        myGrid.Columns.Clear();

        if (Columns != null && Columns.Count > 0)
        {
          foreach (DataGridColumn dataGridColumn in Columns)
          {
            myGrid.Columns.Add(dataGridColumn);
          }
        }


        Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args)
        {
          if (args.NewItems != null)
          {
            UserControl control = ((UserControl)((Grid)myGrid.Parent).Parent);
            foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>())
            {
              /// This is where I tried to fix the exception. ///
              DataGridColumn temp = new DataGridTextColumn();
              temp.Header = column.Header;
              temp.SortMemberPath = column.SortMemberPath;
              control.Dispatcher.Invoke(new Action(delegate()
                {
                  myGrid.Columns.Add(temp);
                }), DispatcherPriority.Normal);
              ////////////////////////////////////////////////////
            }
          }

          if (args.OldItems != null)
          {
            foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>())
            {
              myGrid.Columns.Remove(column);
            }
          }
        };
      }
    }
  }

  public static ObservableCollection<DataGridColumn> GetColumns(DependencyObject iObj)
  {
    return (ObservableCollection<DataGridColumn>)iObj.GetValue(ColumnsProperty);
  }

  public static void SetColumns(DependencyObject iObj, ObservableCollection<DataGridColumn> iColumns)
  {
    iObj.SetValue(ColumnsProperty, iColumns);
  }
}
UserControl control = ((UserControl)((Grid)myGrid.Parent).Parent);
Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args)
        {
          control.Dispatcher.Invoke(new Action(delegate()
          {
            if (args.NewItems != null)
            {
              foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>())
              {
                DataGridColumn temp = new DataGridTextColumn();
                temp.Header = column.Header;
                temp.SortMemberPath = column.SortMemberPath;
                myGrid.Columns.Add(temp);
              }
            }

            if (args.OldItems != null)
            {
              foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>())
              {
                myGrid.Columns.Remove(column);
              }
            }
          }), DispatcherPriority.Normal);
        };
公共静态类DataGridExtension
{
公共静态调度器\u currentDispatcher;
公共静态只读依赖项属性列属性=
DependencyProperty.RegisterAttached(“列”,
类型(可观测采集),
类型(DataGridExtension),
新的UIPropertyMetadata(新的ObservableCollection(),OnDataGridColumnsPropertyChanged));
私有静态无效OnDataGridColumnsPropertyChanged(DependencyObject iObj,DependencyPropertyChangedEventArgs)
{
if(iObj.GetType()==typeof(DataGrid))
{
DataGrid myGrid=iObj作为DataGrid;
ObservableCollection列=(ObservableCollection)iArgs.NewValue;
if(列!=null)
{
myGrid.Columns.Clear();
if(Columns!=null&&Columns.Count>0)
{
foreach(DataGridColumn DataGridColumn in Columns)
{
myGrid.Columns.Add(dataGridColumn);
}
}
Columns.CollectionChanged+=委托(对象发送方,NotifyCollectionChangedEventArgs args)
{
如果(args.NewItems!=null)
{
UserControl=((UserControl)((Grid)myGrid.Parent.Parent);
foreach(args.NewItems.Cast()中的DataGridColumn列)
{
///这就是我试图修复异常的地方///
DataGridColumn temp=新DataGridTextColumn();
临时标题=列标题;
temp.SortMemberPath=column.SortMemberPath;
control.Dispatcher.Invoke(新操作(委托)()
{
myGrid.Columns.Add(临时);
}),DispatcherPriority.Normal);
////////////////////////////////////////////////////
}
}
如果(args.OldItems!=null)
{
foreach(args.OldItems.Cast()中的DataGridColumn列)
{
myGrid.Columns.Remove(column);
}
}
};
}
}
}
公共静态ObservableCollection GetColumns(DependencyObject iObj)
{
返回(ObservableCollection)iObj.GetValue(ColumnsProperty);
}
公共静态void集合列(DependencyObject iObj、ObservableCollection iColumns)
{
iObj.SetValue(ColumnsProperty,iColumns);
}
}
我放置的部分///这是我试图修复异常的部分。///就是抛出异常的地方,正好在myGrid.add(…)

myGrid对象不允许我将该列添加到DataGrid的列集合中。这就是我用Dispatcher.Invoke包围它的原因。奇怪的是,如果我执行myGrid.Columns.Add(newDataGridTextColumn());它可以工作,我可以在视图中看到添加的空列,但是myGrid.columns.Add(temp);抛出异常

这东西一定有什么我不懂的。
请帮忙

编辑以下Stipo建议

<DataGrid ItemsSource="{Binding CollectionView, Source={StaticResource ViewModel}}" local:DataGridExtension.Columns="{Binding DataGridColumns, Source={StaticResource ViewModel}}" AutoGenerateColumns="False" Name="dataGrid">
public static class DataGridExtension
{
  public static Dispatcher _currentDispatcher;

  public static readonly DependencyProperty ColumnsProperty =
    DependencyProperty.RegisterAttached("Columns",
    typeof(ObservableCollection<DataGridColumn>),
    typeof(DataGridExtension),
    new UIPropertyMetadata(new ObservableCollection<DataGridColumn>(), OnDataGridColumnsPropertyChanged));

  private static void OnDataGridColumnsPropertyChanged(DependencyObject iObj, DependencyPropertyChangedEventArgs iArgs)
  {
    if (iObj.GetType() == typeof(DataGrid))
    {
     DataGrid myGrid = iObj as DataGrid;

      ObservableCollection<DataGridColumn> Columns = (ObservableCollection<DataGridColumn>)iArgs.NewValue;

      if (Columns != null)
      {
        myGrid.Columns.Clear();

        if (Columns != null && Columns.Count > 0)
        {
          foreach (DataGridColumn dataGridColumn in Columns)
          {
            myGrid.Columns.Add(dataGridColumn);
          }
        }


        Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args)
        {
          if (args.NewItems != null)
          {
            UserControl control = ((UserControl)((Grid)myGrid.Parent).Parent);
            foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>())
            {
              /// This is where I tried to fix the exception. ///
              DataGridColumn temp = new DataGridTextColumn();
              temp.Header = column.Header;
              temp.SortMemberPath = column.SortMemberPath;
              control.Dispatcher.Invoke(new Action(delegate()
                {
                  myGrid.Columns.Add(temp);
                }), DispatcherPriority.Normal);
              ////////////////////////////////////////////////////
            }
          }

          if (args.OldItems != null)
          {
            foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>())
            {
              myGrid.Columns.Remove(column);
            }
          }
        };
      }
    }
  }

  public static ObservableCollection<DataGridColumn> GetColumns(DependencyObject iObj)
  {
    return (ObservableCollection<DataGridColumn>)iObj.GetValue(ColumnsProperty);
  }

  public static void SetColumns(DependencyObject iObj, ObservableCollection<DataGridColumn> iColumns)
  {
    iObj.SetValue(ColumnsProperty, iColumns);
  }
}
UserControl control = ((UserControl)((Grid)myGrid.Parent).Parent);
Columns.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs args)
        {
          control.Dispatcher.Invoke(new Action(delegate()
          {
            if (args.NewItems != null)
            {
              foreach (DataGridColumn column in args.NewItems.Cast<DataGridColumn>())
              {
                DataGridColumn temp = new DataGridTextColumn();
                temp.Header = column.Header;
                temp.SortMemberPath = column.SortMemberPath;
                myGrid.Columns.Add(temp);
              }
            }

            if (args.OldItems != null)
            {
              foreach (DataGridColumn column in args.OldItems.Cast<DataGridColumn>())
              {
                myGrid.Columns.Remove(column);
              }
            }
          }), DispatcherPriority.Normal);
        };
UserControl=((UserControl)((Grid)myGrid.Parent.Parent);
Columns.CollectionChanged+=委托(对象发送方,NotifyCollectionChangedEventArgs args)
{
control.Dispatcher.Invoke(新操作(委托)()
{
如果(args.NewItems!=null)
{
foreach(args.NewItems.Cast()中的DataGridColumn列)
{
DataGridColumn temp=新DataGridTextColumn();
临时标题=列标题;
temp.SortMemberPath=column.SortMemberPath;
myGrid.Columns.Add(临时);
}
}
如果(args.OldItems!=null)
{
foreach(args.OldItems.Cast()中的DataGridColumn列)
{
myGrid.Columns.Remove(column);
}
}
}),DispatcherPriority.Normal);
};

WPF扩展(可在codeplex中找到)有一个名为
DispatchedObservableCollection
的ObservableCollection扩展版本,在这里非常理想。值得一看并进行相应的定制。

WPF Extension(可在codeplex中找到)有一个名为
DispatchedObservableCollection的扩展版本,在这里非常理想。值得一看并进行相应的定制。

将DataGridColumn创建代码移到dispatcher委托中

发生此问题的原因是DataGridColum