ReactiveUI ViewModelViewHost 与 HandyControl 一起使用时非常慢

ReactiveUI ViewModelViewHost Is Very Slow, When using it With HandyControl

嗨,

大约 6 个月前,我开始使用反应式UI 并用它构建简单的应用程序

就在四个月前,我开始构建一个在低级别监控网络的应用程序

所以,我用 C++ 实现网络部分,然后构建 UI,并在 C# 中构建数据库模型和逻辑

然后创建一个中间库来编组这个低级 API,

如您所知,API 将提供大量数据包。

因此,在 C# 中,我决定使用响应式UI 和响应式编程,一般来说,来处理这些数据流

Rx 工作完美,使用这个高性能反应系统节省了我几天的工作时间

但是现在我遇到了一个大问题:

当我在应用程序中导航时,解析视图/ViewModel 的初始时间 太多了,平均约为 1200-506 ms,这会导致问题,因为这会使应用程序看起来像是冻结的

另外,请注意描述的一个奇怪行为

: 并尝试该解决方案但不起作用。

所以我尝试实现我的自定义 SimpleViewModelViewHost

SimpleViewModelViewHost.xaml

<UserControl x:Class="Sample.EnhancedViewModelViewHost"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             d:DesignHeight="450" d:DesignWidth="800">
    <ContentPresenter
        x:Name="MainContent"
        Content="{Binding Path=View}"
    />
</UserControl>

SimpleViewModelViewHost.xaml.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ReactiveUI;

namespace Sample
{

    // 

    /// <summary>
    /// Interaction logic for EnhancedViewModelViewHost.xaml
    /// </summary>
    public partial class EnhancedViewModelViewHost : UserControl
    {
        public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
            "ViewModel", typeof(object), typeof(EnhancedViewModelViewHost), new PropertyMetadata(default(object)));

        public object ViewModel
        {
            get => GetValue(ViewModelProperty);
            set
            {
                SetValue(ViewModelProperty, value);
                if (value == null) { return; }
                var view = ViewLocator.Current.ResolveView(value);
                if (view != null)
                {
                    View = view;
                    View.ViewModel = value;

                }
                else
                {
                    MainContent.Content = value;
                }
            }
        }


        public static readonly DependencyProperty ViewProperty = DependencyProperty.Register(
            "View", typeof(IViewFor), typeof(EnhancedViewModelViewHost), new PropertyMetadata(default(IViewFor)));

        public IViewFor View
        {
            get => (IViewFor)GetValue(ViewProperty);
            set => SetValue(ViewProperty, value);
        }

        public EnhancedViewModelViewHost()
        {
            DataContext = this;
            InitializeComponent();
        }
    }
}


我知道这次泄露了很多功能disposing of old view/viewModel .....

但现在性能不错:现在只需要 250-300 ms,但仍然一点也不好 因为人眼可以注意到这种延迟

所以现在我遇到了一个大问题,所以我在 ReactiveUI 中创建了另一个带有空视图的简单应用程序

没有绑定

你猜怎么着:问题仍然存在

我使用 Visual studio 分析器来跟踪 start of a constructor of ViewModel 之间的时间

WhenActivated in the View

的结尾

所以我的问题是:反应团队是否意识到这个问题,或者只是我做错了什么,如果是,解决方案是什么

另请注意:

我尝试通过 Creating 提高复杂布局的性能并实现一个名为 IHotReloadViewModel 的接口并实现一些逻辑以重用当前 ViewModel 而不是替换它

并获得性能 from about 1350 ms -> 10 ms


片段

视图模型的一部分

 public class ManageProjectsViewModel : ReactiveObject, IActivatableViewModel
    {

        // .....
        [Reactive] public EditProjectViewModel SelectedProject { get; set; }
        //.....

        private AppDbManager AppDbManager { get; set; }

        #region Commands

        public ReactiveCommand<Unit, Unit> EditProject { get; set; }
        public ReactiveCommand<Unit, Unit> CreateNewProject { get; set; }
        public ReactiveCommand<Unit, Unit> DeleteProject { get; set; }
        // ....

        #endregion

        private IDisposable LastProjectTrack { get; set; }

        private Subject<Unit> FreeSelectedProject { get; set; }

        public ManageProjectsViewModel()
        {
            Activator = new ViewModelActivator();
            AppDbManager = Locator.Current.GetService<AppDbManager>();

            #region Commands

            var canOperateOnProject = this.WhenValueChanged(vm => vm.SelectedProjectLookup).Select(p => p != null);
            EditProject = ReactiveCommand.Create(EditProjectImpl, canOperateOnProject);
            CreateNewProject = ReactiveCommand.Create(CreateNewProjectImpl);
            DeleteProject = ReactiveCommand.Create(DeleteProjectImpl, canOperateOnProject);

            #endregion

            FreeSelectedProject = new Subject<Unit>();

            this.WhenActivated(disposables =>
            {
                ProjectAddedNotify.ObserveOnDispatcher().Subscribe(ProjectAddedNotifyImpl).DisposeWith(disposables);

                FreeSelectedProject.ObserveOnDispatcher().Subscribe(FreeSelectedProjectImpl).DisposeWith(disposables);
            });


        }

// ...........

View.xaml.cs

的一部分

 public partial class ManageProjectsView : ReactiveUserControl<ManageProjectsViewModel>
    {
        private bool called = false;
        public ManageProjectsView()
        {
            InitializeComponent();

            IDisposable mainDisposable = null;

            mainDisposable = this.WhenActivated(disposable =>
            {

              // ........

                this.BindCommand(ViewModel, vm => vm.CreateNewProject, v => v.NewProject).DisposeWith(disposable);
                this.BindCommand(ViewModel, vm => vm.EditProject, v => v.EditProject).DisposeWith(disposable);
                this.BindCommand(ViewModel, vm => vm.DeleteProject, v => v.DeleteProject).DisposeWith(disposable);
                this.Bind(ViewModel, vm => vm.SelectedProject, v => v.SelectedProject.ViewModel).DisposeWith(disposable);

                ProjectLookups.Events().SelectionChanged.Subscribe(args =>
                {
                    if (args.AddedItems.Count > 0)
                    {
                        ViewModel.SelectedProjectLookup = (NPProjectLookup)args.AddedItems[0];
                    }
                }).DisposeWith(disposable);

                ProjectLookups.ApplyHorizontalScrolling();
                ProjectLookups.AllowZoom();

                mainDisposable.DisposeWith(disposable);

            }, this); // either use this or not: performance issue exists
        }
    }

大部分Views/ViewModels使用相同的结构


那么为什么我认为这是一个问题

因为我用我的 ViewModel-View Locator 的简单实现测试了相同的 UI 并且一切都立即工作

还使用 Prism With DryIoC i work with it for a long time 对其进行了测试,一切都立即有效

所以知道有什么解决方案吗,或者我需要在当前的反应式UI 应用程序中使用棱镜?

通知


更新 (1)

在测试了多个应用后 5 apps 我发现

更新 (2)

我创造了This Issue On ReactiveUI Repository 谢谢

请你创建一个可用的问题复制品,把它放在 github 存储库中,link 在这里,并在 https://github.com/reactiveui/ReactiveUI/issues

中创建一个问题

至于"not providing any performance considerations"的问题。在 pull request 期间有很多关于性能和影响的讨论(即 https://github.com/reactiveui/ReactiveUI/pull/1311 https://github.com/reactiveui/ReactiveUI/pull/1289 and https://github.com/reactiveui/splat/pull/360). In terms of benchmarks, indeed we're short on them, but we have an open issue https://github.com/reactiveui/ReactiveUI/issues/1734。文档可能会更好,那里有很多关于如何充分利用 ReactiveUI 的知识,欢迎人们提供帮助我们改进了使这些知识易于访问的方法。

至于对一个5000星的项目的信心。 5000 颗星很好地表明了兴趣,但 兴趣。帮助维护它的人数约为 1%,其中 少数 人将他们的时间和热情花在一个项目上,有些人将近十年。他们希望人们使用该项目并希望帮助您从中获得最大收益。您想对自己使用的东西充满信心,这只是明智的,但是 公司在实时应用程序中使用它 and\or 每天有成千上万的用户使用的应用程序。

我可以向您指出有关 NET 框架的帖子,其星等比我们大,而且它也有 perf\knowledge\usability 个问题。但我的观点是,项目的维护者只能通过 customers\communities 尝试和反馈来学习。

对于您的实际问题,有一群人愿意提供帮助。但我们需要可重现问题的证据,最好是通过测试并可能跟踪您所看到的内容。然后我们可以协助并了解您的项目是否正在做我们可以帮助解决的事情,或者 ReactiveUI 或底层 Splat 库是否需要一些调查。