C# WPF数据网格多线程崩溃

C# WPF数据网格多线程崩溃,c#,wpf,multithreading,datatable,wpfdatagrid,C#,Wpf,Multithreading,Datatable,Wpfdatagrid,我有一个视图,其中有一个DataGrid。 视图模型为DataContext,我可以在其中访问背景对象中的DataTable。 后台对象必须使用数据表,并保持更新。 还允许用户更改该数据表 如果我创建了DataTable的副本,它将停止崩溃,但用户显然没有处理数据 如果我让用户打开访问权限,程序必然会崩溃 下面是一个将崩溃的简短程序: app.cs public partial class App : Application { public App() { So

我有一个视图,其中有一个
DataGrid
。 视图模型为
DataContext
,我可以在其中访问背景对象中的
DataTable
。 后台对象必须使用
数据表
,并保持更新。 还允许用户更改该
数据表

如果我创建了
DataTable
的副本,它将停止崩溃,但用户显然没有处理数据

如果我让用户打开访问权限,程序必然会崩溃

下面是一个将崩溃的简短程序:

app.cs

public partial class App : Application
{
    public App()
    {
        SomeBackgroundThing background = new SomeBackgroundThing();
        MainWindowViewModel viewmodel = new MainWindowViewModel(background);
        MainWindowView view = new MainWindowView(viewmodel);
        view.Show();
    }
}
主xaml

<Window x:Class="NullPointerDataGrid.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid Name="datagrid" ItemsSource="{Binding Path=table, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
    </Grid>
</Window>
Stacktrace只显示“Externer代码”,因此没有要跟踪的堆栈

问题是WPF崩溃了-我的代码可以处理它。。。不知何故,我需要封装WPF,这样它就不会崩溃,其中一种方法是复制DataTable——但随后我失去了写回该表的能力,因为当某些内容被编辑时,不会调用它的setter

编辑#2:


我重新创建了这个示例,以显示我在另一个程序中遇到的错误,我刚刚发现崩溃实际上与滚动条有关。如果我将显示数据的数量更改为一个较低的数字,以便没有滚动条,代码将不会崩溃。

以下对viewmodel的更改解决了问题

我现在使用的是wpf的一个副本,并且只注意出现的CANGE。这段代码有一个不完善的变更机制的问题——但这超出了这个问题的范围

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private SomeBackgroundThing thing;

    private DataTable wpftable;
    public DataTable table
    {
        get
        {
            lock (wpftable)
            {
                return wpftable;
            }

        }

        set
        {
            lock (wpftable)
            {
                wpftable = value;
            }
        }
    }

    public MainWindowViewModel(SomeBackgroundThing thing)
    {
        wpftable = thing.table.Copy();
        this.thing = thing;
        thing.Changed += new EventHandler(thing_Changed);
    }

    void thing_Changed(object sender, EventArgs e)
    {
        if (PropertyChanged != null)
        {
            DataTable wpftablecopy = wpftable.Copy();
            DataTable thintablecopy = thing.table.Copy();
            int rowcount = wpftablecopy.Rows.Count;
            for (int col = 0; col < 4; col++)
            {
                for (int row = 0; row < rowcount; row++)
                {
                    if (wpftablecopy.Rows[row][col] != thintablecopy.Rows[row][col])
                        wpftable.Rows[row][col] = thintablecopy.Rows[row][col];
                }
            }
            PropertyChanged(this, new PropertyChangedEventArgs("table"));
        }
    }
}
public类MainWindowViewModel:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私人背景;
私有数据表wpftable;
公共数据表
{
得到
{
锁(wpftable)
{
返回wpftable;
}
}
设置
{
锁(wpftable)
{
wpftable=值;
}
}
}
公共主窗口视图模型(一些背景)
{
wpftable=thing.table.Copy();
这个;
thing.Changed+=新事件处理程序(thing\u Changed);
}
已更改无效内容(对象发送者、事件参数)
{
if(PropertyChanged!=null)
{
DataTable wpftablecopy=wpftable.Copy();
DataTableThintableCopy=thing.table.Copy();
int rowcount=wpftablecopy.Rows.Count;
for(int col=0;col<4;col++)
{
对于(int row=0;row
您是否有例外情况?如果是这样,请编辑您的问题并添加验证消息和stacktrace。根据设计,后台线程无法访问UI对象。我怀疑它正在崩溃,因为它试图更新UI。UI不会每次都检查线程是否正确,因此您可能需要进行一些更新,以使您相信这不是问题所在。但它确实挂得很快,而且挂得不好。我不确定这就是问题所在,但我可以说我也有类似的问题和症状。我所做的是让UI RO在后台处理一个副本,然后在回调中将UI绑定到处理过的副本,并使UI RW。
System.NullReferenceException wurde nicht behandelt.
  Message=Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
  Source=PresentationFramework
  InnerException: 
public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private SomeBackgroundThing thing;

    private DataTable wpftable;
    public DataTable table
    {
        get
        {
            lock (wpftable)
            {
                return wpftable;
            }

        }

        set
        {
            lock (wpftable)
            {
                wpftable = value;
            }
        }
    }

    public MainWindowViewModel(SomeBackgroundThing thing)
    {
        wpftable = thing.table.Copy();
        this.thing = thing;
        thing.Changed += new EventHandler(thing_Changed);
    }

    void thing_Changed(object sender, EventArgs e)
    {
        if (PropertyChanged != null)
        {
            DataTable wpftablecopy = wpftable.Copy();
            DataTable thintablecopy = thing.table.Copy();
            int rowcount = wpftablecopy.Rows.Count;
            for (int col = 0; col < 4; col++)
            {
                for (int row = 0; row < rowcount; row++)
                {
                    if (wpftablecopy.Rows[row][col] != thintablecopy.Rows[row][col])
                        wpftable.Rows[row][col] = thintablecopy.Rows[row][col];
                }
            }
            PropertyChanged(this, new PropertyChangedEventArgs("table"));
        }
    }
}