【问题标题】:Updating DataTable causes crash更新 DataTable 导致崩溃
【发布时间】:2014-07-23 23:16:41
【问题描述】:

当我在 DataTable 中插入一行并选择了视图时,我的应用程序似乎崩溃了。大概这与一些跨线程问题有关,但我不完全确定如何解决它。这是我对 DataTable 的定义:

public class Logging
{
    public DataTable Logs;

    public Logging()
    {
        Logs = new DataTable();
        Logs.Columns.Add("Level", typeof(int));
        Logs.Columns.Add("Message", typeof(string));
    }

    public void LogMessage(int level, string message)
    {
        DataRow row = Logs.NewRow();
        row["Level"] = level;
        row["Message"] = message;
        Logs.Rows.Add(row);
    }
}

这会按我的预期生成 DataTable,并且工作正常。然后我将它绑定到 WPF ListView 控件,如下所示:

    <ListView x:Name="lvConsole">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Level" Width="50" DisplayMemberBinding="{Binding Path=Level}"/>
                <GridViewColumn Header="Message" Width="376" DisplayMemberBinding="{Binding Path=Message}"/>
            </GridView>
        </ListView.View>
    </ListView>

也可以通过将其添加到 C# 中:

lvConsole.ItemsSource = Util.Logger.Logs.DefaultView;

因此,为了产生问题,我只需打开包含列表视图的表单,单击它并滚动一下,我会收到以下错误:

An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll

Additional information: An ItemsControl is inconsistent with its items source.

查看更多细节,这似乎是根本问题:

{"Information for developers (use Text Visualizer to read this):\r\nThis exception was thrown because the generator for control 'System.Windows.Controls.ListView Items.Count:20' with name 'lvConsole' has received sequence of CollectionChanged events that do not agree with the current state of the Items collection.  The following differences were detected:\r\n  Accumulated count 12 is different from actual count 20.  [Accumulated count is (Count at last Reset + #Adds - #Removes since last Reset).]\r\n\r\nOne or more of the following sources may have raised the wrong events:\r\n     System.Windows.Controls.ItemContainerGenerator\r\n      System.Windows.Controls.ItemCollection\r\n       System.Windows.Data.BindingListCollectionView\r\n        System.Data.DataView\r\n(The starred sources are considered more likely to be the cause of the problem.)\r\n\r\nThe most common causes are (a) changing the collection or its Count without raising a corresponding event, and (b) raising an event with an incorrect index or item parameter.\r\n\r\nThe exception's stack trace describes how the inconsistencies were detected, not how they occurred.  To get a more timely exception, set the attached property 'PresentationTraceSources.TraceLevel' on the generator to value 'High' and rerun the scenario.  One way to do this is to run a command similar to the following:\n   System.Diagnostics.PresentationTraceSources.SetTraceLevel(myItemsControl.ItemContainerGenerator, System.Diagnostics.PresentationTraceLevel.High)\r\nfrom the Immediate window.  This causes the detection logic to run after every CollectionChanged event, so it will slow down the application.\r\n"}

有人知道我需要做什么来解决这个问题吗?我尝试了很多方法,其中之一是:

private static object _syncLock = new object();

BindingOperations.EnableCollectionSynchronization(Logs.Rows, _syncLock);

这似乎没有做任何有用的事情,也许它与我同时从两个线程调用 LogMessage 有关?

【问题讨论】:

    标签: c# wpf datatable


    【解决方案1】:

    我很确定我找到了一个很好的解决方法,但不确定它会持续多久。无论如何我都会分享它,希望它是正确的......

        private void logMessage(object parameters)
        {
            object[] Paras = (object[])parameters;
            int level = Convert.ToInt32(Paras[0]);
            string message = (string)(Paras[1]);
            DataRow row = Logs.NewRow();
            row["Level"] = level;
            row["Message"] = message;
            Logs.Rows.Add(row);
        }
    
        public void LogMessage(int level, string message)
        {
            object lvl = Convert.ToString(level);
            object msg = message;
            object[] ob = { lvl, msg };
            if (Util.client.player.isRunning)
            {
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ParameterizedThreadStart(logMessage), ob);
                ParameterizedThreadStart pts = new ParameterizedThreadStart(logMessage);
            }
        }
    

    我必须创建一个新方法,它使用应用程序调度程序调用编辑列表的方法,如果我是正确的,它将从应用程序主线程编辑列表(巧合的是,不是那个写入列表,但不断显示它的那个)。

    这一切都相当混乱,如果其他人能想到更好的方法来解释它,请继续:)

    【讨论】:

      猜你喜欢
      • 2021-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 2021-12-07
      • 2019-12-17
      • 2017-01-29
      • 1970-01-01
      相关资源
      最近更新 更多