【问题标题】:ReactiveUI ViewModelViewHost Is Very Slow, When using it With HandyControl [closed]ReactiveUI ViewModelViewHost 非常慢,与 HandyControl 一起使用时 [关闭]
【发布时间】:2020-05-10 05:55:36
【问题描述】:

嗨,

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

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

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

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

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

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

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

但现在我有一个大问题:

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

  • 所以我尝试解决这个问题,或者解决它但没有任何帮助,

  • 我跟踪了响应式 UI 的大部分/所有指南,但似乎没有任何效果

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

in this StackOverflow question: WhenActivated is called twice: 并尝试该解决方案,但不起作用。

所以我尝试实现我的自定义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
{

    // https://stackoverflow.com/questions/36433709/whenactivated-is-called-twice-when-used-in-views-and-viewmodels-hosted-in-viewmo/36813328#36813328

    /// <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 -&gt; 10 ms


片段

ViewModel 的一部分

 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
        }
    }

大多数视图/视图模型使用相同的结构


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

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

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

那么知道是否有任何解决方案,或者我需要在当前的响应式 UI 应用程序中使用棱镜?

通知

  • 首先我没有在 Github 的响应式 UI 问题中发布此问题:因为我不想让问题面板溢出可能不必要的问题,所以我需要在这里确定其他用户设备上是否存在此问题,如果我会报告它给响应式 UI 团队

更新 (1)

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

  • 调用WhenActivated Twice的问题与reactiveUI有关
  • 性能问题Delay of view 仅在使用带有HandyControl UI 库的ReactiveUI 时发生,我仍然无法确定问题的根源,但因为它仅在使用HCRI 时发生,我决定创建This Issue at HandyControl in GitHub

更新(2)

我创建了This Issue On ReactiveUI Repository 谢谢。

【问题讨论】:

  • 为什么用 (-) 关闭?这里发生了什么:说不能生产,我在两个库上提供了两个问题,并将完整的源代码链接到这些库存储库的问题,并带有一个完整的项目来重现问题?另外,如果管理员看到这个:@DPVreony 的回答在这里消失了两天,我现在才来发现它又出现了??所以我在这些问题上说这条评论被删除了!

标签: wpf reactiveui viewmodellocator


【解决方案1】:

您能否创建一个可用的问题复制品,将其放在 github 存储库中,在此处链接并在 https://github.com/reactiveui/ReactiveUI/issues 中创建一个问题

关于“不提供任何性能考虑”的问题。在拉取请求期间有很多关于性能和影响的讨论(即https://github.com/reactiveui/ReactiveUI/pull/1311https://github.com/reactiveui/ReactiveUI/pull/1289https://github.com/reactiveui/splat/pull/360)。就基准而言,我们确实缺乏它们,但我们有一个未解决的问题https://github.com/reactiveui/ReactiveUI/issues/1734 供他们使用。文档可能会更好,那里有很多关于如何充分利用 ReactiveUI 的知识,欢迎人们帮助我们改进如何使这些知识可访问。

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

我可以向您指出有关 NET 框架的帖子,该框架的星数比我们大,而且它也存在性能\知识\可用性问题。但我的观点是,项目的维护者只能通过客户\社区的尝试和反馈来学习。

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

【讨论】:

  • 谢谢,首先当我谈到性能时,我的意思是影响一个非常简单的应用程序的关键性能问题,那么 largr 应用程序呢!但无论如何我认为这是一个误解,来自我写的东西,对此感到抱歉,其次我将创建一个简单的存储库来演示这个问题,我会附上来自两个真实应用程序的视频,它们有同样的问题,再次感谢你。
猜你喜欢
  • 2014-03-25
  • 2014-08-11
  • 1970-01-01
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
相关资源
最近更新 更多