C# Winform INotifyPropertyChanged 刷新页面

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using OMRON.Compolet.CIP;

namespace WindowsFormsApp3
{
    public partial class Form1 : Form
    {
        public static NJCompolet nJCompolet;
        Thread th1;
        public Customer customer;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            CheckForIllegalCrossThreadCalls = false;
            customer = new Customer();
            customer.CustomerName = "";
            customer.PhoneNumber = "";
            nJCompolet = new NJCompolet();
            nJCompolet.LocalPort = 2;
            nJCompolet.PeerAddress = "192.168.250.1";
            nJCompolet.Active = true;
            dataBind();
            th1 = new Thread(DoWork);
            th1.Start();
        }
        private void dataBind() {

            this.Invoke(new Action(() =>
            {
                textBox1.DataBindings.Add("Text", customer, "CustomerName");
                textBox2.DataBindings.Add("Text", customer, "PhoneNumber");
            }));

        }

        private void DoWork() {
            while (true)
            {
                object obj = null;
                obj = nJCompolet.ReadVariable("StruckReal.A");
                if (obj != null) {
                    customer.CustomerName = obj.ToString();
                }
                obj = nJCompolet.ReadVariable("StruckReal.B");
                if (obj != null)
                {
                    customer.PhoneNumber = obj.ToString();
                }
            }
            }
    }
    public class CustomerBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    }
        public class Customer : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private string _customerName;
            private string _phoneNumber;
            public string CustomerName
            {
                get { return _customerName; }
                set
                {
                    if (_customerName != value)
                    {
                        _customerName = value;
                    //OnPropertyChanged("CustomerName");
                    
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CustomerName)));
                }
                }
            }


            public string PhoneNumber
            {
                get { return _phoneNumber; }
                set
                {
                    if (_phoneNumber != value)
                    {
                        _phoneNumber = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PhoneNumber)));
                }
                }
            }

        }

    }

//封装--无需再添加绑定

    public class Class1 : NotifyPropertyChangedBase
    {
        private int A;
        public int MyProperty { 
            get { return this.A; }
            set
            {
                if (A != value)
                {
                    A = value;
                    RaisePropertyChanged();//注意这里可以省略属性名称
                }
            }
        }

    }

    public class NotifyPropertyChangedBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

//chatgpt

当在WinForms中使用 INotifyPropertyChanged 时,当数据绑定的控件处于不同的线程上下文时,会发生“跨线程异常”。解决此问题的一种方法是确保在更改属性时始终在UI线程上下文中发出 PropertyChanged 事件。可以通过将代码包装在 Control.InvokeControl.BeginInvoke 方法中来实现此目的。

以下是在使用INotifyPropertyChanged时避免跨线程异常的示例代码:

 

c#复制代码

// ViewModel class implementing INotifyPropertyChanged
public class MyViewModel : INotifyPropertyChanged
{
    private string _myProperty;
    
    public string MyProperty
    {
        get { return _myProperty; }
        set 
        { 
            if (_myProperty != value)
            {
                _myProperty = value;
                
                // Raise the PropertyChanged event on the UI thread
                if (PropertyChanged != null)
                {
                    Control control = Application.OpenForms[0];
                    control.Invoke(new Action(() =>
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("MyProperty"));
                    }));
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

在上面的示例代码中,我们首先检查 _myProperty 的值是否与要设置的新值相同。如果它们不同,则更新该值,并且在 UI 线程上下文中引发 PropertyChanged 事件。这里 Application.OpenForms[0]表示当前正在运行的窗体,你需要根据你的应用程序来选择正确的窗体。

注意:使用 Control.InvokeControl.BeginInvoke 方法可能会导致性能瓶颈。如果有大量的属性更改需要在 UI 线程上下文中发出 PropertyChanged 事件,可以考虑将其放入队列中,并使用后台线程异步处理队列中的项。

除了使用 Control.Invoke 或 Control.BeginInvoke 方法,还有一些其他方法可以避免在 WinForms 应用程序中出现跨线程异常。

  1. 使用 SynchronizationContext

.Net Framework 提供了一个抽象类 SynchronizationContext,用于协调异步操作之间的通信。在 WinForms 应用程序中,可以使用 WindowsFormsSynchronizationContext,它是 SynchronizationContext 的派生类,专门为在 UI 线程上下文中执行代码而设计。

以下是使用 WindowsFormsSynchronizationContext 的示例代码:

 

c#复制代码

public class MyViewModel : INotifyPropertyChanged
{
    private string _myProperty;
    private readonly WindowsFormsSynchronizationContext _syncContext;

    public MyViewModel()
    {
        _syncContext = WindowsFormsSynchronizationContext.Current;
    }
    
    public string MyProperty
    {
        get { return _myProperty; }
        set 
        { 
            if (_myProperty != value)
            {
                _myProperty = value;
                
                // Raise the PropertyChanged event on the UI thread
                if (PropertyChanged != null)
                {
                    _syncContext.Post(new SendOrPostCallback(_ =>
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("MyProperty"));
                    }), null);
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

 

在上面的示例代码中,我们首先获取当前的 SynchronizationContext,并将其存储在字段 _syncContext 中。然后,在设置属性值时,我们使用 _syncContext.Post 方法将 PropertyChanged 事件的引发推迟到 UI 线程上下文中。

  1. 使用 TaskScheduler

.NET Task Parallel Library 提供了一个 TaskScheduler 类,可用于在特定的上下文中执行代码。在 WinForms 应用程序中,可以使用 TaskScheduler.FromCurrentSynchronizationContext 方法获取 UI 线程的任务调度程序。

以下是使用 TaskScheduler 的示例代码:

 

c#复制代码

public class MyViewModel : INotifyPropertyChanged
{
    private string _myProperty;
    private readonly TaskScheduler _uiTaskScheduler;

    public MyViewModel()
    {
        _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    }
    
    public string MyProperty
    {
        get { return _myProperty; }
        set 
        { 
            if (_myProperty != value)
            {
                _myProperty = value;
                
                // Raise the PropertyChanged event on the UI thread
                if (PropertyChanged != null)
                {
                    Task.Factory.StartNew(() =>
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("MyProperty"));
                    }, CancellationToken.None, TaskCreationOptions.None, _uiTaskScheduler);
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

在上面的示例代码中,我们首先使用 TaskScheduler.FromCurrentSynchronizationContext 方法获取 UI 线程的任务调度程序。然后,在设置属性值时,我们使用 Task.Factory.StartNew 方法将 PropertyChanged 事件的引发封装到一个任务中,并使用 _uiTaskScheduler 参数指定该任务应在 UI 线程上下文中执行。

总之,这些方法都可以解决在 WinForms 应用程序中使用 INotifyPropertyChanged 时出现的跨线程异常问题。选择哪种方法取决于你的实际需求和个人偏好。

  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
c是C语言(C programming language)的简称。C语言是一种结构化的、高级的、通用的程序设计语言,由贝尔实验室的Dennis Ritchie在1972年发明。C语言具有简洁、高效、可移植等特点,被广泛应用于系统软件、嵌入式软件和应用软件的开发中。 C语言的语法简洁明了,易于学习和理解。它提供了丰富的程序控制结构,可以实现条件判断、循环迭代等功能,使程序的编写更加灵活。 C语言的编译过程也相对简单。C语言程序需要经过编译器(如GCC)的编译之后才能执行,编译器将C语言代码转换成机器码,然后在计算机上运行。这种编译方式使得C语言程序的执行效率较高,适合开发对性能要求较高的应用。 C语言具有良好的可移植性。由于C语言是面向过程的编程语言,不依赖于特定的硬件平台和操作系统,因此C语言程序可以在不同的计算机系统上进行移植,提高了开发效率和软件的可复用性。 C语言在各个领域都有广泛的应用。它可以用于开发操作系统、数据库管理系统、编译器等系统软件;还可以用于开发嵌入式系统的驱动程序、控制程序等;同时也可以用于开发各种应用软件,如游戏、办公软件、图像处理等。 总之,C语言是一种非常重要且有影响力的编程语言,它的简洁性、高效性和可移植性使得它在计算机领域拥有广泛的应用。对于想要学习编程的人来说,掌握C语言是一个很好的入门选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值