c# - 从 Winforms MVP 中的模型事件更新 UI(被动视图)
问题描述
在使用 MVP(被动视图)模式时必须更新 UI 的模型触发的事件(不是 UI 事件,如按钮单击、窗口调整大小等)处理的最佳方法是什么?
有很多类似的问题询问如何从后台线程、事件等更新 UI。但是,所有答案似乎都建议使用该Control.Invoke
方法,这对于简单的 Winforms 应用程序来说很好,但不能在以下情况下使用使用 MVP 模式。
最简单的方法是在演示者中使用SynchronizationContext
对象吗?然后使用该SynchronizationContext.Post
方法在 UI 线程上运行事件代码。
我正在使用 .NET Framework 4.8 版
解决方案
这些是我提出的不使用Control.Invoke
的解决方案。
IMainView
、MainView
和的代码Program
在两种解决方案中都是相同的:
主视图
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
}
}
}
此解决方案使用一个对象,在构造函数中使用UI 进行TaskFactory
初始化。TaskScheduler
引发事件时,使用该TaskFactory
对象启动新任务。
推荐阅读
- java - 如何在 AppCompatActivity 之后添加多个实现?
- node.js - 在 Node.js 路由中添加 isAuthenticated 并不能防止未经身份验证的访问
- php - 关于 Laravel 中的紧凑方法
- django - 删除视图不会删除对应的对象
- ios - display_timer_callback:滚动时出现意外状态
- python-3.x - transform() 接受 2 个位置参数,但给出了 3 个
- powerpoint - Powerpoint:用于复制图形的透明 UI(如描图纸)
- python - 为什么 range() 不接受关键字参数?
- flutter - 使用提供者登录
- laravel - 无法使用 xdebug 在 netbeans 中调试 laravel 项目