任何普遍接受的模式,用于存储SynchronizationContext或其他视图模型对象以编组到Ui线程上?

时间:2018-05-03 02:46:15

标签: c# wpf multithreading xaml synchronizationcontext

我的问题现在已经改变了:我正在寻找一个“正确”的模式,以便能够在视图模型中存储SynchronizationContext 某些 else ;所以我可以将外部调用者重新组合回窗口的线程。

我的目标:

  1. 在视图模型中获取一个平台无关的对象,允许编组回到此窗口的线程。
  2. 如果执行代码是否在正确的同步上下文中,则能够测试
  3. 如果视图模型有一些可以来自任意线程的传入代码,那么如何编组到窗口的线程上? --- AND,我不想存储Dispatcher;为了更加平台无关。

    曾经调度员抽象,但我摆脱了它,因为我认为核心中的SynchronizationContext 库可以更好地完成工作......处理抽象也稍微麻烦一些;并且,SynchronizationContext甚至可以自己进行子类化。

    所以我将当前SynchronizationContext存储在视图模型构造函数中,并使用一种方法来测试当前上下文是否相等,并确定是否需要发布到存储的上下文中。下面是一个问题:Wpf实际上在事件处理程序上创建了包装器,并且SynchronizationContext相等的检查基本上都是假的。

    我现在还发现了BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstancehttps://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;
        }
    }
    

0 个答案:

没有答案