【问题标题】:c# dataGridView random cells location change (Edit: Inter Process Synchronization?)c# dataGridView 随机单元格位置更改(编辑:进程间同步?)
【发布时间】:2010-12-26 11:46:21
【问题描述】:

我有一个 dataGridView,它基于 DataTable 显示来自 DataView 的数据。 DataTable 从后台线程以高频率更新(通常一次一行),但具有不同的规律性,即有时更新之间的时间为 0.5 毫秒,其他几毫秒。由于 datagridview 绑定到 DataView,我不发送刷新 datagridview 的请求。 我遇到的问题是我有时会在不应该出现的地方绘制单元格,即如附图所示:http://radlak.com/dataGridViewError1.png

编号为 122.94 的行在红色列中绘制了蓝色单元格(灰色列是 DataTable 的 PrimaryKey,DataView 是按此排序的)。这不应该发生,因为唯一的蓝色单元格应该留在第二列。有时,第三列的单元格会显示在其他地方。有谁知道这种行为的原因是什么? 有什么办法可以消除吗?除此之外,我对更新速度没有任何问题 - 其他一切似乎都运行得非常快而且没问题。 我将非常感谢有关此问题的任何帮助。 谢谢, 马丁

附: dataGridView1 是双缓冲的。

【问题讨论】:

    标签: c# multithreading datagridview datatable


    【解决方案1】:

    闻起来像赛车。网格还没有吞下一个更新,而你又用另一个更新了。更新进程和 UI 线程之间有同步吗?

    如果您批量更新并且每隔一段时间(即每 100 毫秒)应用一次更新,可能会有所帮助。毕竟是供人阅读的 UI,再快点刷新也没有意义。

    编辑

    批处理的一种方法是让更新线程将更新应用到单独的数据结构(列表?数组?)并创建另一个线程,每 0.1 秒将修改从数据结构复制到用户界面。

    您尝试使用的锁的问题是,如果相同的对象未锁定在 GridView 中,则在代码中应用锁并没有任何好处。而 GridView 对你的锁一无所知

    【讨论】:

    • 非常感谢,我也是这么想的。这就是我在行更新时应用锁定命令的原因,但这似乎还不够。我试图锁定整个表、dataview 和 datagridview,但这也没有完成这项工作。我认为这是我正在努力解决的部分 - 同步。最好的方法是什么?对我来说,关键是要达到一个点,当 datagridview 更新正确而无需批量更新时,然后对它们进行批处理以达到最高速度。感谢您的帮助
    • 另外,更新过程基于外部发生的事件。每当有新数据可用时,就会调用偶数函数。这使得同步变得更加复杂,以至于我不确定如何等待新事件被处理,直到 datagridview 被更新。
    • 最后,我肯定会牺牲 datagridview 更新来支持事件处理。我需要 datagridview 来检查一切是否正常。很抱歉有多个 cmets,但这些想法是“批量”浮现在我脑海中的 ;)
    • 我认为这是缺少的:如何通知更新过程(正在等待监视器)关于 gui datagridview 完成更新?在谷歌上找不到。通常人们会问如何反其道而行之。
    • 也许如果您以合理的速率对计时器进行更新,则无需将计时器线程与 UI 同步。您仍然需要同步计时器和更新程序,但两者都在您手中
    【解决方案2】:

    我可以查询吗:

    • 你有一个DataTable
    • 你有一个DataGridView,绑定到那个桌子上的DataView
    • 不同的线程上,您正在更新DataTable

    ?

    是的,那行不通。表单具有线程关联性,您的更改事件将在错误的线程上触发。仅在后台线程上更新 DataTable 是不行的。在我看来,您需要考虑批量处理您要进行的更改,并使用this.Invoke 要求UI 线程 进行更改;那么它应该可以工作:

    public override void OnDataArrival()
    {
        // here on background thread
        this.Invoke((MethodInvoker)delegate {
            // here on UI thread
            //TODO: update DataTable
        });
    }
    

    这将涉及线程之间的跳跃(通过this.Invoke),因此希望批量更改。

    【讨论】:

    • 感谢您的回复。如上面的代码所示,我正在使用 Invoke 来初始化数据网格,我注意到,一旦成功执行了该调用方法,我就不必重复从 OnDataArrival 调用的更新。我假设,一旦 datagridview 收到对 tbl 的引用,它就会停留在那里并且不需要任何进一步的通知。似乎在 inoking dDelegateInitializeGrid 正确通知 datagridview 后从 DataTable 更新事件,但是由于我不知道如何控制这些事件,它们会在每次 DataTable 更新时触发创建竞赛条件。
    • 我不确定我是否更准确地解释了一件事:当程序开始执行时,正在执行的第一个函数是 OnInitialization,我在其中初始化了 Windows 窗体。
    • 这越来越令人沮丧...根据我在互联网上的发现,如果datagridview位于更新过程之外的其他线程中,则它不应反映数据源中的更改。但是,我注意到,通过在开始时调用datagridinitialization,源中的所有更改稍后都会反映在 datagridview 中。即使我不想。我尝试在 DataTable 上使用 Merge 来制作它的副本,并在计时器上更新网格,但仍然发生同样的事情 - 每次数据到达时都会更新网格。这是正常行为还是我做错了什么?谢谢
    • 如果您在非 UI 线程上对数据绑定源进行了更新,则您犯了一个错误...
    • 我认为这里的很多混乱是因为 UI 不是每个人都习惯的主线程。如果它是主要的,我认为不会有任何问题。
    【解决方案3】:

    以防万一有人有时间查看代码,我附上了一个在单独的线程中包含 Timer 并在单独的线程中形成的代码:

    namespace MyNamespace
    {
        public delegate void DelegateInitializeGrid(DataView tbl);
    
        public class MyMainClass : Strategy
        {
            RunForm runForm;
            Thread oThread;
            Thread tThread;
    
            public delegate void updateGridCallback(DataTable tbl);
    
            private DataTable tbl = new DataTable();
            public DataTable ctbl = new DataTable();
            private DataView vtbl;
            public DataView cvtbl;
            DataRow dr;
    
            DataRow t;
            DataRow[] tt;
    
            System.Threading.Timer clock;
            bool frst = true;
    
            public override void OnInitialization()
            {
                tbl.Columns.Add("Col1", typeof(int));
                tbl.Columns.Add("Col2", typeof(double));
                tbl.Columns.Add("Col3", typeof(int));
                tbl.Columns.Add("Price", typeof(System.Decimal));
                DataColumn[] PrimaryKeyColumns = new DataColumn[1];
                PrimaryKeyColumns[0] = tbl.Columns["Price"];
                tbl.PrimaryKey = PrimaryKeyColumns;
    
                runForm = new RunForm();
                oThread = new Thread(new ThreadStart(runForm.startForm));
                oThread.Start();
    
                tThread = new Thread(new ThreadStart(startTimer));
                tThread.Start();
            }
    
            void startTimer()
            {
                clock = new System.Threading.Timer(new TimerCallback(Timer_Tick));
                clock.Change(0, 1000);
                Thread.Sleep(Timeout.Infinite);
            }
    
            void Timer_Tick(object state)
            {
                if (frst == true)
                {
                    ctbl.Merge(tbl);
                    cvtbl = new DataView(ctbl);
                    cvtbl.Sort = "Price DESC";
    
                    frst = false;
    
                    runForm.sampleForm.Invoke(runForm.sampleForm.dDelegateInitializeGrid,
                        vtbl);
                }
    
                Console.WriteLine("tick occured");
                ctbl.Merge(tbl);
            }
    
            public override void onDataArrival()
            {
                //update DataTable tbl
            }
    
            public override void OnStop()
            {
                runForm.stopForm();
                clock.Dispose();
                tThread.Abort();
    
            }
    
        }    
    
        public class RunForm
        {
    
            public Form1 sampleForm = null;
            public DataTable dtbl;
    
            public void startForm()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                sampleForm = new Form1();
                Application.Run(sampleForm);
            }
            public void stopForm()
            {
                sampleForm.Dispose();
            }
        }
    
    
    
        partial class Form1
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
    
    
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should bedisposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                    //aTimer.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Windows Form Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                // initialize form and datagridview
    
            }
    
            #endregion
    
            public System.Windows.Forms.DataGridView dataGridView1;
    
            private void initializeGrid(DataView lst)
            {
                SetDoubleBuffered(dataGridView1);
                //this.DoubleBuffered = true;
                this.dataGridView1.ReadOnly = true;
                this.dataGridView1.DataSource = lst;
            }
        }
    
        public partial class Form1 : Form
        {
            public DelegateInitializeGrid dDelegateInitializeGrid;
    
            public Form1()
            {
                InitializeComponent();
                dataGridView1.AutoGenerateColumns = true;
                dDelegateInitializeGrid = new DelegateInitializeGrid(this.initializeGrid);
            }
    
            public static void SetDoubleBuffered(Control control)
            {
                // set instance non-public property with name "DoubleBuffered" to true
                typeof(Control).InvokeMember("DoubleBuffered",
                    BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                    null, control, new object[] { true });
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      相关资源
      最近更新 更多