实现自己的“工厂”以重用 WPF 中的视图

2024-05-04

我目前正在使用WAF(WPF 应用程序框架) http://waf.codeplex.com/discussions/361216用于 WPF 编程。 我真的很喜欢为我的应用程序中的每个小视图单元拥有一个自己的 ViewModel 的想法,我随后以这种方式实现了它。

在我的项目中,我得到了一个复杂的列表,其中每个列表元素还包含一个列表。由于复杂性,每个列表和列表列表元素都是一个自己的 ViewModel。 “最坏情况”场景总共包含 60-90 个视图模型,仅适用于列表视图。

(这是一个问题列表,其中每个问题都有一个带有评级和其他 ui 元素的答案列表)。

这个实现效果很好,但性能很差。经过分析后,我发现当我在一组问题之间切换时,错误会导致创建我的 ViewModel(因为必须再次生成整个列表)。

当我在问题集之间切换时,我无法 1:1 重复使用我的视图,因为问题数量不同。

但是,我认为我可以重用给定的视图模型,并在必要时添加(如果新集需要更多视图)更多视图模型。

因此我编写了以下工厂:

[Export]
public class ViewModelPerformanceFactory<T> where T : IPerformanceFactoryViewModel
{
    private List<T> _collection;
    private int _index;
    private readonly ExportFactory<T> _exportFactory;

    [ImportingConstructor]
    public ViewModelPerformanceFactory(ExportFactory<T> exportFactory)
    {
        _exportFactory = exportFactory;
        _index = 0;
    }

    public void Reset()
    {
        _index = 0;
        if (_collection == null)
        {
            return;
        }
        foreach (var elem in _collection)
        {
            elem.Reset();
        }
    }

    public T Get()
    {
        if (_collection == null)
        {
            _collection = new List<T>();
        }
        if (_collection.Count <= _index)
        {
            _collection.Add(_exportFactory.CreateExport().Value);
        }
        return _collection[_index++];
    }
}

where IPerformanceViewModel只是提供一个Reset-清除ViewModel和View的方法。

因此,每次加载新问题集时,我都会调用 ViewModelPerformanceFactory 的重置函数,该函数会清除所有模型并将索引设置回 0(因此,如果有人需要新的 viewmodel 实例,它将创建第一个) 。

从理论上讲,这非常有效。

现在我的问题/问题:我在问题集之间切换的次数越多,我的应用程序就越慢......这不是视图模型对象的加载 - 这很好。我的列表看起来非常非常慢 - 有时甚至卡住几秒钟,然后继续增加......

我认为这是一个 WAF 问题,因为每个 ViewModel 都会实例化一个 View,请参阅:

protected ViewModel(TView view) : base(view)
    {
        this.view = view;
    }
}

似乎我无法像 WAF 中的 ViewModel 那样轻松地重用视图。

有人对我有建议或者可能有其他方法来加速我的申请吗?或者有人认为我的整个方法很愚蠢并且我根本停止编程? ;)

编辑:有时似乎存在内存/性能泄漏,但并非每次都可重现..:(


我不确定您的方法或为什么存在性能问题,但这是我对类似问题的解决方案。

完整的解决方案可以找到https://github.com/steinborge/ProxyTypeHelper/wiki https://github.com/steinborge/ProxyTypeHelper/wiki

我想要实现的是创建“通用”视图模型的能力,然后可以将其分配给数据模板。数据模板只是一个用户控件。如果您有很多简单的数据维护屏幕,则可以节省大量重复代码。

但有几个问题。数据模板在具有泛型的 XAML 中不能很好地工作,如果您有大量数据模板,那么您将创建大量 XAML - 特别是如果您想在单独的视图中使用它。在您的例子中,您提到最多 90 个视图 - 这将是大量的 XAML。

解决方案是将模板存储在查找中,并根据 DataContext 使用内容控件和 DataTemplateSelector 进行填充。所以首先需要注册数据模板/视图:

       manager.RegisterDataTemplate(typeof(GenericViewModel<CarType, WPFEventInter.ViewModel.CarTypeViewModel>), typeof(WPFEventInter.UserControls.CarTypesView));
       manager.RegisterDataTemplate(typeof(GenericViewModel<Colour, WPFEventInter.ViewModel.ColourViewModel>), typeof(WPFEventInter.UserControls.ColourView));

RegisterDataTemplate 只是将数据模板添加到字典中:

   public void RegisterDataTemplate(Type viewModelType, Type dataTemplateType, string Tag="")
    {
        var template = BuildDataTemplate(viewModelType, dataTemplateType) ;
        templates.Add(viewModelType.ToString() + Tag, template);
    }

    private DataTemplate BuildDataTemplate(Type viewModelType, Type viewType)
    {
        var template = new DataTemplate()
        {
            DataType = viewModelType,
            VisualTree = new FrameworkElementFactory(viewType)
        };

        return template;
    }

现在使用 ContentPresenter 控件创建一个视图。这将根据视图的 Datacontext 显示视图。

DataTemplateSelector 如下所示。这将根据数据上下文返回适当的视图:

public class ContentControlGenericTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate retVal = null;
        try
        {
            retVal = Core.WPF.Infrastructure.DataTemplateManager.templates[item.GetType().ToString()];
        }
        catch //empty catch to prevent design time errors..
        {
        }

        return retVal;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实现自己的“工厂”以重用 WPF 中的视图 的相关文章

  • 如何调试参数化 SQL 查询

    我使用 C 连接到数据库 然后使用 Ad hoc SQL 来获取数据 这个简单的 SQL 查询非常方便调试 因为我可以记录 SQL 查询字符串 如果我使用参数化 SQL 查询命令 有没有办法记录 sql 查询字符串以进行调试 我想就是这样的
  • 将 2D 数组映射到 1D 数组

    我想用一维数组来表示一个二维数组 函数将传递两个索引 x y 和要存储的值 这两个索引代表一维数组的单个元素 并相应地设置它 我知道一维数组需要具有 arrayWidth arrayHeight 的大小 但我不知道如何设置每个元素 例如 如
  • 测试 hdf5/c++ 中的组是否存在

    我正在打开一个现有的 HDF5 文件来附加数据 我想向那个叫做的小组保证 A存在以供后续访问 我正在寻找一种简单的方法来创建 A有条件地 如果不存在则创建并返回新组 或者返回现有组 一种方法是测试 A存在 我怎样才能高效地做到这一点 根据
  • 使用 C# 使用应用程序密码登录 Office 365 SMTP

    在我们的 Office 365 公司帐户中实施两步身份验证之前 我的 C WPF 程序已成功进行身份验证并发送邮件 我使用了 SmtpClient 库 但现在我必须找到另一个解决方案 因为它不再起作用 我找不到任何使用 O365 应用程序密
  • 如何避免选择项目时 winforms 树视图图标发生变化

    我正在一个小型 C Winforms 应用程序中尝试树视图 我已经以编程方式将 ImageList 分配给树视图 并且所有节点都很好地显示了它们的图标 but当我单击一个节点时 它的图标会发生变化 变为 ImageList 中的第一个图像
  • 捕获当前正在播放的声音

    是否可以捕获计算机上当前播放的声音 如果能够将其保存为 mp3 就好了 但我认为这样做会存在一些法律问题 所以 wav 也可以 我环顾四周 有人建议使用虚拟音频线之类的东西 在 C 中捕获声音输出 https stackoverflow c
  • CMake - 将预构建库链接到 C# 项目

    我正在使用 CMake 构建 C 库 该库依赖于已构建的库 dll 我似乎无法让图书馆链接到我的图书馆 我尝试过使用target link libraries mylib external lib 我也尝试过暴力破解 reference e
  • for 循环 - 没有效果的语句

    由于某种原因 我收到错误 statement with no effect关于这个声明 for j idx j lt iter j increment printf from loop idx i int idx punc ctxt j 你
  • _mm_max_ss 在 clang 和 gcc 之间有不同的行为

    我正在尝试使用 clang 和 gcc 交叉编译一个项目 但在使用时发现一些奇怪的差异 mm max ss e g m128 a mm set ss std numeric limits
  • 为什么以下代码不允许我使用 fgets 获取用户输入但可以使用 scanf?

    这是一个更大程序的简短摘录 但该程序的其余部分无关紧要 因为我认为我能够隔离该问题 我怀疑这与我使用 fgets 的方式有关 我读过 最好使用 fgets 而不是 scanf 但我似乎无法让它在这里正常工作 当我使用以下代码时 程序不会给我
  • C#:如何使用 SHOpenFolderAndSelectItems [重复]

    这个问题在这里已经有答案了 有人可以举例说明如何使用 shell 函数吗SH打开文件夹并选择项目 http msdn microsoft com en us library bb762232 VS 85 aspx来自 C 我不太明白如何使用
  • 在可观察项目生成时对其进行处理

    我有一个IObservable它会生成一次性物品 并且在其生命周期内可能会生成无限数量的物品 因此 我想在每次生成新项目时处理最后一个项目 因此Using http reactivex io documentation operators
  • 使用 Linq 进行异步Where过滤

    我有一个List通过填充的元素async调用 WebService 没问题 我需要过滤该列表以便在应用程序视图上显示某些内容 我试过这个 List
  • 标准 C 中的 sizeof 与 sizeof()? [复制]

    这个问题在这里已经有答案了 我看到一些直接使用 sizeof 的代码 想知道它是否是标准 C 令我惊讶的是 它运行得很好 这是一个例子 include
  • 如何在 C++ 中使用 PI 常数

    我想在一些 C 程序中使用 PI 常数和三角函数 我得到三角函数include
  • SSBO 是更大的 UBO?

    我目前正在 OpenGL 4 3 中使用 UBO 进行渲染 以将所有常量数据存储在 GPU 上 诸如材料描述 矩阵等内容 它可以工作 但是 UBO 的小尺寸 我的实现为 64kB 迫使我多次切换缓冲区 减慢渲染速度 我正在寻找类似的方法来存
  • 在 unix 中编译 dhrystone 时出错

    我是使用基准测试和 makefile 的新手 我已经从下面的链接下载了 Dhrystone 基准测试 我正在尝试编译它 但我遇到了奇怪的错误 我尝试解决它 但没有成功 有人可以帮助我运行 dhrystone 基准测试吗 以下是我尝试编译的两
  • 从 C# 中的 .NET SecureString 读取单个字符?

    WPF 的PasswordBox 返回一个SecureString 它对窥探者隐藏密码 问题是你最终必须获得密码的值 而我在网上找到的建议都涉及将值复制到字符串中 这会让你回到窥探者的问题 IntPtr bstr Marshal Secur
  • ASP.NET Core:会话 ID 始终变化

    今天启动了一个全新的 ASP NET Core 网站 按照说明添加会话 我们在索引页上打印出会话 ID 它始终是唯一的 我认为这可能是 cookie 合规性 所以我在 Chrome 的高级设置和调试器中删除了所有 cookie 但横幅不会再
  • 最后从同一类中的其他构造函数调用构造函数

    我在这里读到可以调用另一个构造函数从同一类中的另一个构造函数调用构造函数 https stackoverflow com questions 829870 calling constructor from other constructor

随机推荐

  • Ruby 中的数字运算(需要优化)

    Ruby 可能不是最适合这种情况的语言 但我很乐意在我的终端中使用它 所以这就是我要使用的 我需要处理从 1 到 666666 的数字 因此我找出包含 6 但不包含 7 8 或 9 的所有数字 第一个数字是6 下一个16 then 26等等
  • 如何在Django表单中设置密码显示/隐藏眼睛按钮

    首先 我将尝试使用原生 HTML 和 jquery 来解决这个问题 但我想以 Django 形式解决这个问题 而不需要任何脚本 我会尝试this https itsolutionstuff com post bootstrap show h
  • 如何在R中使用twoord.plot()绘制多个图(分面)?

    我的数据看起来像这样 height lt c 1 2 3 4 2 4 6 8 weight lt c 12 13 14 15 22 23 24 25 person lt c Jack Jim Jill Tess Jack Jim Jill
  • 如何为导航抽屉的菜单项赋予颜色?

    我正在创建导航抽屉 我看到 Play 商店有彩色菜单图标 我想知道我该怎么做 我尝试在菜单图标上按颜色过滤器应用颜色 但应用程序强制关闭 这是我的代码 menu menu
  • 使用 JArray 从 JSON 获取值

    我有以下字符串 json 格式 我从我的服务器得到 ruta 1 division 7 ruta 2 division 7 ruta 3 division 7 ruta 4 division 7 ruta 5 division 7 ruta
  • 带有 xml 样式表的 XslTransform

    好像大家都说如果使用XslTransform 会先调用Load加载样式表 然后调用Transform进行转换 但是我有以下 XML 文件 我是否应该先加载xml 找到样式表节点 然后调用Load来加载样式表 或者还有其他方法吗 是处理指令
  • 为什么这个 C++ STL 分配器不分配?

    我正在尝试编写一个派生自的自定义 STL 分配器std allocator 但不知何故所有的电话allocate 去基础班 我已将范围缩小到以下代码 template
  • 创建持久身份验证 cookie 时出现问题:ASP.NET MVC

    好的 这是我创建身份验证 cookie 的代码 get user s role List
  • 找出右键单击的 DOM 元素

    我使用以下代码片段来构建自定义上下文菜单
  • AudioTrack 可以播放 MIDI 文件吗?

    我想知道AudioTrack Android可以播放MIDI文件吗 如果没有的话哪个库可以 因为我想要 Android 库 可以为我的应用程序播放和控制 MIDI 文件的速度 从这里检查 Android 支持的媒体格式Android 媒体支
  • NodeJS + Express + Mongo 会话存储

    我目前在尝试在 MongoDb 中存储会话时遇到了很大的麻烦 我尝试过express session mongo和connect mongodb 当我尝试加载登录页面时 两者都给出了相同的 500内部服务器错误 这让我觉得也许在某个地方与
  • 使用 Poppler Qt4 C++

    我需要在我的应用程序中使用 pdf 查看器库 我使用 C 和 QT 我下载了Poppler http poppler freedesktop org 和代码示例Poppler Qt4 界面库 http people freedesktop
  • 从应用程序访问 iCloud Drive 文件

    我希望我的应用程序支持 iCloud 以便我可以存储和获取 PDF 文件 我的问题是 如何在不使用 iCloud 的情况下访问 iCloud 驱动器文件UIDocumentPickerViewController 实际上我想在我的应用程序中
  • 如何以编程方式检测我的应用程序是否在 ASP.NET 页面中以 IIS 7.0 集成模式运行

    一般来说 我们应该控制我们的 AppPools 并能够强制使用托管管道模式 就我而言 我没有控制权 并且希望根据托管管道模式 集成与经典 以稍微不同的方式实现代码背后的代码 我只是不知道如何检测到这一点 有没有一种简单的方法可以从代码隐藏页
  • 使用 MapBox GL JS 无需访问令牌

    有没有办法使用MapBox GL JS没有访问令牌 我在文档中找不到任何提示MapBox GL JS https docs mapbox com mapbox gl js api 然而 Uber建议是可以通过他们的图书馆 https ube
  • 如何设置 MPEG-4 文件的“媒体创建”日期

    我有许多从各种数码相机格式转码的 MPEG 4 文件 其文件系统修改日期是正确的 我想设置 媒体创建 标签来匹配 这可以通过 属性 窗口的 详细信息 选项卡在 Windows 资源管理器中手动完成 设置 媒体创建 非常有用 因为 Windo
  • 强制 WcfSvcHost.exe 使用我的自定义服务主机

    是否可以强制 WcfSvcHost 当我执行 F5 或在解决方案中调试另一个项目时自动执行 使用自定义 ustom 服务 通过使用服务工厂 我的自定义服务主机在我的 asp net 主机容器中运行良好 该服务工厂又调用自定义服务库 但是当
  • 使用 ExecuteSqlCommand 调用存储过程(需要未提供的参数)

    我正在尝试使用 EF 调用存储过程context Database ExecuteSqlCommand因为我的参数之一是数据表 以下是该过程的参数 ALTER PROCEDURE mySchema myProc customerId INT
  • 由于 MSVCR110.dll,MS Visual Studio 2012 Ultimate 无法启动

    当我尝试运行 MVS 2012 时 我总是收到错误 在库 DLL MSVCR110 dll 中找不到过程 crtCreateSymbolicLinkW 的入口点 我已经从我的另一台计算机复制了这个 dll 文件 一切正常 但没有帮助0 o
  • 实现自己的“工厂”以重用 WPF 中的视图

    我目前正在使用WAF WPF 应用程序框架 http waf codeplex com discussions 361216用于 WPF 编程 我真的很喜欢为我的应用程序中的每个小视图单元拥有一个自己的 ViewModel 的想法 我随后以