-1

你好,

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

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

因此,我在 C++ 中实现网络部分,然后在 C# 中构建 UI、数据库模型和逻辑

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

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

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

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

但是现在我有一个大问题:

当我浏览应用程序时,解析视图 / ViewModel 的初始时间非常长,大约1200-506 ms是平均水平,这会导致问题,因为这会使应用程序看起来像是被冻结了

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

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

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

在这个 StackOverflow 问题中:WhenActivated 被调用两次:并尝试该解决方案但不起作用。

所以我尝试实现我的自定义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 Profiler 来跟踪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,一切都立即运行

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

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

注意

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

更新 (1)

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

更新 (2)

我在 ReactiveUI 存储库上创建了这个问题 谢谢。

4

1 回答 1

2

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

至于“不提供任何性能考虑”的问题。在拉取请求期间有很多关于性能和影响的讨论(即https://github.com/reactiveui/ReactiveUI/pull/1311 https://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 库是否需要进行一些调查。

于 2020-05-10T09:14:27.433 回答