【问题标题】:Update UI from model events in Winforms MVP (Passive view)从 Winforms MVP 中的模型事件更新 UI(被动视图)
【发布时间】:2020-08-31 02:29:51
【问题描述】:

在使用 MVP(被动视图)模式时必须更新 UI 的模型触发的事件(不是 UI 事件,如按钮单击、窗口大小调整等)的最佳方法是什么?

有很多类似的问题询问如何从后台线程、事件等更新 UI。但是,所有答案似乎都建议使用 Control.Invoke 方法,这对于简单的 Winforms 应用程序来说很好但在使用MVP模式时不能使用。

最简单的方法是在演示者中使用SynchronizationContext 对象吗?然后使用SynchronizationContext.Post方法在UI线程上运行事件代码。

我使用的是 .NET Framework 4.8 版

【问题讨论】:

    标签: c# multithreading winforms user-interface mvp


    【解决方案1】:

    这些是我提出的不要使用Control.Invoke的解决方案。

    IMainViewMainViewProgram 的代码在两种解决方案中是相同的:

    IMainView

    namespace Tester1
    {
        interface IMainView
        {
            string ControlProperty { get; set; }
        }
    }
    

    主视图

    using System.Windows.Forms;
    
    namespace Tester1
    {
        public partial class MainView : Form, IMainView
        {
            public MainView()
            {
                InitializeComponent();
            }
    
            public string ControlProperty
            {
                get => MyControl.Text;
                set => MyControl.Text = value;
            }
        }
    }
    

    程序

    using System;
    using System.Windows.Forms;
    
    namespace Tester1
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                // models
                EventRaisingObject eventRaisingObject = new EventRaisingObject();
    
                // views
                MainView mainView = new MainView();
    
                // presenters
                MainPresenter mainPresenter = new MainPresenter(mainView, eventRaisingObject);
    
                Application.Run(mainView);
            }
        }
    }
    

    解决方案 1:使用SynchronizationContext

    主演讲者

    using System.Threading;
    
    namespace Tester1
    {
        class MainPresenter
        {
            private readonly IMainView mainView;
            private readonly EventRaisingObject eventRaisingObject;
    
            private readonly SynchronizationContext viewContext;
    
            public MainPresenter(IMainView mainView, EventRaisingObject eventRaisingObject)
            {
                this.mainView = mainView;
    
                viewContext = SynchronizationContext.Current;
    
                this.eventRaisingObject = eventRaisingObject;
                this.eventRaisingObject.MyEvent +=
                    (sender, s) => viewContext.Post(d => OnMyEvent(s), null);
            }
    
            private void OnMyEvent(string e)
            {
                // do some work
    
                mainView.ControlProperty = e;
    
                // do some work
            }
        }
    }
    

    此解决方案使用SynchronizationContext 对象,在构造函数中使用 UI 的上下文进行初始化。

    解决方案 2:使用TaskFactory

    using System.Threading.Tasks;
    
    namespace Tester1
    {
        class MainPresenter
        {
            private readonly IMainView mainView;
            private readonly EventRaisingObject eventRaisingObject;
    
            private readonly TaskFactory viewTaskFactory;
    
            public MainPresenter(IMainView mainView, EventRaisingObject eventRaisingObject)
            {
                this.mainView = mainView;
    
                viewTaskFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
    
                this.eventRaisingObject = eventRaisingObject;
                this.eventRaisingObject.MyEvent +=
                    (sender, s) => viewTaskFactory.StartNew(() => OnMyEvent(s));
            }
    
            private void OnMyEvent(string e)
            {
                // do some work
    
                mainView.ControlProperty = e;
    
                // do some work
            }
        }
    }
    

    此解决方案使用 TaskFactory 对象,在构造函数中使用 UI 的 TaskScheduler 进行初始化。引发事件时,使用 TaskFactory 对象启动新任务。

    【讨论】:

      猜你喜欢
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-13
      相关资源
      最近更新 更多