实现自己的“工厂".在WPF中重用视图 [英] Implementing an own "Factory" for reusing Views in WPF

查看:81
本文介绍了实现自己的“工厂".在WPF中重用视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用 WAF(WPF应用程序框架)在WPF中进行编程. 我真的很喜欢为我的应用程序中的每个小型View-Unit拥有一个自己的ViewModel的想法,随后我以这种方式实现了该

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

(这是一个问题列表,其中每个问题都有一个包含评分和其他ui元素的答案列表).

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

当我在问题集之间切换时,由于没有相同数量的问题,所以无法以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++];
    }
}

其中IPerformanceViewModel仅提供Reset-方法来清除ViewModel和View.

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

理论上,这很好.

现在要问的问题是:我在问题集之间切换的次数越多,我的应用程序就越慢...这不是加载viewmodel-objects-很好.我的列表看起来非常非常慢-有时甚至停留了几秒钟,然后继续增加...

我认为这是一个WAF问题,因为每个ViewModel都可以实例化一个View,参见:

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

似乎我无法像在WAF中那样方便地重用Views.

有人对我有建议吗,或者还有其他加快我的应用程序速度的方法吗?还是有人认为我的整个方法是愚蠢的,而我却根本停止了编程? ;)

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

解决方案

没有看到您的完整代码,很难说出您的问题所在.但是从您提供的描述中猜测:

  1. 绝对切换到DataTemplates和HierarchicalDataTemplates.如果每次更改数据都在创建新的控件,您将永远不会看到出色的性能.这也使您能够使用虚拟化.

  2. 您的应用程序变慢的事实确实表明内存泄漏.最常见的原因是未取消订阅的事件.

  3. 假设视图模型少于100个,则实例化ViewModel不应花费大量时间.如果是这种情况,您应该寻找导致他们花费这么长时间的原因.您不应该重复使用包装模型对象的ViewModels.如果这样做,则需要大量记账以重置"它们,或者它们必须是无状态的,这半打败了将它们放在首位的目的.

  4. 对于MVVM,ViewModel引用View的事实是一个主要的难题.在我的大多数解决方案中,我什至没有一个视图类,除了自定义控件(如DateTimeBoxes和自定义ComboBoxes)之外,我都使用DataTemplates.

I'm currently using WAF (WPF Application Framework) for programming in WPF. I really like the idea to have an own ViewModel for every small View-Unit in my application which I subsequently implemented in this way.

In my project I got a complex list in which every list-element also contains a list. Each list and list-list element is an own ViewModel because of the complexity. The "worst-case" scenario contains 60-90 viewmodels in total, just for the list-view.

(It's a list of questions where each question has a list of answers with ratings and other ui elements).

This implementation works great but the performance is quite bad. After profiling I found out that the error results in creating my ViewModels when I switch between one set of questions (because the whole list has to be generated again).

When I switch between the question-sets I can't reuse my views 1:1 as there are not the same number of questions.

However, I thought I could reuse the given viewmodels and add (in case the new set requires more views) more viewmodels if necessary.

Therefore I've written the following Factory:

[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 just offers a Reset-Method to clear the ViewModel and View.

So every time a new question-set is loaded, I call the reset-function of my ViewModelPerformanceFactory which clears all models and set the index back to 0 (so if someone requires a new instance of viewmodel, it will get the first one created).

In theory, this works great.

Now to my question/problem: The more often I switch between my question-sets the slower my application is... It's not the loading of the viewmodel-objects - this is fine. My list just appears very very slow - sometimes even stuck for a few seconds and then continues to build up...

I think this is a WAF-problem as every ViewModel instanciates a View see:

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

and it seems like I can't reuse Views as easy as ViewModels in WAF.

Does anyone have a suggestion for me or maybe another approach to speed-up my application? Or does anyone think my whole approach is stupid and I shut stop programming at all? ;)

Edit: There seems to be a memory/performance leak sometimes, but not reproducable every time.. :(

解决方案

Without seeing your entire code, it is difficult to say what your problems are. But guessing from the description you provided:

  1. Absolutely switch to DataTemplates and HierarchicalDataTemplates. If you are creating new controls each time you change data, you will never see stellar performance. This will enable you to use virtualization as well.

  2. The fact that your application is getting slower does indeed indicate a memory leak. Most common cause is events that are not being unsubscribed.

  3. Instantiating ViewModels should not take any significant time given that there are less than 100 of them. If this is the case, you should look for the cause of why they are taking that long. You should not be reusing ViewModels wrapping model objects. If you do, you need a lot of book keeping to 'reset' them, or they have to be stateless, which semi-defeats the purpose of having them in the first place.

  4. The fact that the ViewModel references the View is a major no-go in regards to MVVM. In most of my solutions, I don't even have a view class, I use DataTemplates for everything except custom controls like DateTimeBoxes and custom ComboBoxes.

这篇关于实现自己的“工厂".在WPF中重用视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆