我的问题现在已经改变了:我正在寻找一个“正确”的模式,以便能够在视图模型中存储SynchronizationContext
或某些 else ;所以我可以将外部调用者重新组合回窗口的线程。
我的目标:
如果视图模型有一些可以来自任意线程的传入代码,那么如何编组到窗口的线程上? --- AND,我不想存储Dispatcher
;为了更加平台无关。
我曾经调度员抽象,但我摆脱了它,因为我认为核心中的SynchronizationContext
库可以更好地完成工作......处理抽象也稍微麻烦一些;并且,SynchronizationContext
甚至可以自己进行子类化。
所以我将当前SynchronizationContext
存储在视图模型构造函数中,并使用一种方法来测试当前上下文是否相等,并确定是否需要发布到存储的上下文中。下面是一个问题:Wpf实际上在事件处理程序上创建了包装器,并且SynchronizationContext
相等的检查基本上都是假的。
我现在还发现了BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance
:https://docs.microsoft.com/en-us/dotnet/api/system.windows.basecompatibilitypreferences?view=netframework-4.7
但是这让我对这种方法感到疑惑,因为现在默认行为是返回新实例,不更改平台默认值时,可能性能更高或更优化...... < / p>
是否有一些最佳方式让视图模型能够发布,和进行可靠的检查?我做也想进行检查,因为有些代码需要知道它是否会异步发布...
我现在也在使用窗口构造函数中调用SetSynchronizationContext
的概念(因为我有一个窗口工厂);但这看起来很可能是hacky。也许我需要再次处理自己的抽象......在像这样的视图模型中处理它有点麻烦。
下面的应用程序代码仅说明了我发现的内容:跟踪启动,我正在查看SynchronizationContext
。主窗口打开主窗口---这是唯一的线程---并且有一个Dispatcher SynchronizationContext
。在按钮的命令处理程序中,回调是使用不同的SynchronizationContext
进行调用。 (但它仍然在主线程上。)和,这些上下文不相等。
节目输出:
App OnStartup: SynchronizationContext.Current: 26765710
MainWindowVIewModel ctor: SynchronizationContext.Current: 26765710
MainWindow ctor: SynchronizationContext.Current: 26765710
Command Execute: SynchronizationContext.Current: 1048160
所有代码:
using System;
using System.Threading;
using System.Windows;
namespace WpfApp1
{
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
=> Console.WriteLine(
"App OnStartup:"
+ " SynchronizationContext.Current:"
+ $" {SynchronizationContext.Current.GetHashCode()}");
}
}
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnMainWindowClose">
<Application.Resources/>
</Application>
using System;
using System.Threading;
namespace WpfApp1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Console.WriteLine(
"MainWindow ctor:"
+ " SynchronizationContext.Current:"
+ $" {SynchronizationContext.Current.GetHashCode()}");
}
}
}
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfApp1="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="232"
Width="422">
<Window.DataContext>
<wpfApp1:MainWindowVIewModel/>
</Window.DataContext>
<Grid>
<Button Content="Button"
HorizontalAlignment="Left"
Margin="80,44,0,0"
VerticalAlignment="Top"
Width="75"
Command="{Binding Command}"/>
</Grid>
</Window>
using System;
using System.Threading;
using System.Windows.Input;
namespace WpfApp1
{
public class MainWindowVIewModel
{
public MainWindowVIewModel()
=> Console.WriteLine(
"MainWindowVIewModel ctor:"
+ " SynchronizationContext.Current:"
+ $" {SynchronizationContext.Current.GetHashCode()}");
public ICommand Command { get; }
= new Command();
}
}
using System;
using System.Threading;
using System.Windows.Input;
namespace WpfApp1
{
public class Command
: ICommand
{
public bool CanExecute(object parameter)
=> true;
public void Execute(object parameter)
=> Console.WriteLine(
"Command Execute:"
+ " SynchronizationContext.Current:"
+ $" {SynchronizationContext.Current.GetHashCode()}");
public event EventHandler CanExecuteChanged;
}
}