【发布时间】:2018-06-16 01:09:08
【问题描述】:
我创建了一些测试代码,以便尝试找出如何在 UWP 中正确使用多个窗口。我想看看我是否可以触发一个事件并让多个窗口在事件处理程序中更新它们的 UI。我终于得到了一些工作,但我不完全确定它为什么工作。
这是在我的页面中创建的课程
public class NumberCruncher
{
private static Dictionary<int, Tuple<CoreDispatcher, NumberCruncher>> StaticDispatchers { get; set; }
static NumberCruncher()
{
StaticDispatchers = new Dictionary<int, Tuple<CoreDispatcher, NumberCruncher>>();
}
public NumberCruncher()
{
}
public event EventHandler<NumberEventArgs> NumberEvent;
public static void Register(int id, CoreDispatcher dispatcher, NumberCruncher numberCruncher)
{
StaticDispatchers.Add(id, new Tuple<CoreDispatcher, NumberCruncher>(dispatcher, numberCruncher));
}
public async Task SendInNumber(int id, int value)
{
foreach (var dispatcher in StaticDispatchers)
{
await dispatcher.Value.Item1.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Debug.WriteLine($"invoking {dispatcher.Key}");
dispatcher.Value.Item2.NumberEvent?.Invoke(null, new NumberEventArgs(id, value));
});
}
}
}
这是我的 MainPage 代码的相关部分
NumberCruncher numberCruncher;
public MainPage()
{
this.InitializeComponent();
numberCruncher = new NumberCruncher();
numberCruncher.NumberEvent += NumberCruncher_NumberEvent;
}
private async void NumberCruncher_NumberEvent(object sender, NumberEventArgs e)
{
listView.Items.Add($"{e.Id} sent {e.Number}");
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
NumberCruncher.Register(ApplicationView.GetForCurrentView().Id, Window.Current.Dispatcher, numberCruncher);
}
我有一个按钮可以创建 MainPage 的新视图。然后我有另一个按钮调用SendInNumber() 方法。
当我导航到 MainPage 时,我为窗口和 NumberCruncher 实例注册了 Dispatcher。然后在触发事件时,我使用 NumberCruncher EventHandler 来处理特定的 Dispatcher。
这不会引发封送处理异常。如果我尝试使用当前类的 EventHandler
await dispatcher.Value.Item1.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Debug.WriteLine($"invoking {dispatcher.Key}");
NumberEvent?.Invoke(null, new NumberEventArgs(id, value));
});
尝试将项目添加到 listView 时,我收到了封送处理异常。但是,如果我在 MainPage 中维护 SynchronizationContext,然后使用 SynchronizationContext.Post 更新 listView。效果很好
SynchronizationContext synchronizationContext;
public MainPage()
{
this.InitializeComponent();
numberCruncher = new NumberCruncher();
numberCruncher.NumberEvent += NumberCruncher_NumberEvent;
synchronizationContext = SynchronizationContext.Current;
}
private async void NumberCruncher_NumberEvent(object sender, NumberEventArgs e)
{
synchronizationContext.Post(_ =>
{
listView.Items.Add($"{e.Id} sent {e.Number}");
}, null);
}
但是,这不起作用,并在尝试更新 listView 时引发编组异常。
private async void NumberCruncher_NumberEvent(object sender, NumberEventArgs e)
{
await CoreApplication.GetCurrentView().CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
listView.Items.Add($"{e.Id} sent {e.Number}");
});
}
这是怎么回事?
【问题讨论】:
-
GetCurrentView 返回指向活动窗口的指针,不一定是包含您尝试更新的 listView 实例的窗口。所以我认为你最终会使用错误的 UI 线程(因为每个窗口都有自己的 UI 线程)。您是否尝试过使用“listView.Dispatcher”?这应该将调用编组到此 listView 实例的正确 UI 线程上。
-
文档说 GetCurrentView 返回活动视图,但我设置了一个线程,将 ApplicationView.GetForCurrentView().Id 和 CoreApplication.GetCurrentView().IsMain 的状态打印到调试控制台。当我有 2 个窗口时,每个窗口的输出都不同。这让我相信 GetCurrentView() 返回该 UI 线程的视图,而不是活动窗口。
-
是的,但是您的事件是否在 UI 线程上触发?如果是这样,那么您首先不需要调度程序。您似乎需要它的事实表明该事件不会在与您尝试更新的 ListView 对应的 UI 线程上触发。如果您只执行“listView.Dispatcher.RunAsync”会发生什么? (而不是 CoreApp.GetCurrentView().CoreWin.Dispatcher.RunAsync)
-
如果我使用 listView Dispatcher,我会在我打开的每个窗口的 listView 中收到一条消息,因此我会在窗口 -23473 上看到
-23473 sent 123两次打开两个窗口。
标签: c# windows multithreading uwp multiple-views