繁体   English   中英

MVVM应用程序中的复杂WPF UserControl

[英]Complex WPF UserControl in MVVM application

接管了现有WPF应用程序的维护后,我惊异地发现,两个Views和ViewModels中有大块几乎相同的代码。 显然,我想对其进行重构,以便它们都可以重用单个功能块,但是我不确定在架构上如何做到最好。

identikit代码用于处理选项卡中的UI数据。 但是,我对此进行了拆分,其他标签中的代码(这两种情况有所不同)至关重要,可以访问我需要拆分的标签的属性和对象。

更复杂的是,复制的代码需要数据库访问。 我们有一个存储库对象来处理这个问题。 通常,在创建新对象时,我通过将存储库的副本传递到构造函数中来使其可测试。 但是,如果在这种情况下这样做,我将有两个存储库对象副本-一个在ViewModel中,一个在拆分后的代码中-需要处理同一数据,这将导致并发问题。

我最初的想法是为此制作一个UserControl,但是我对它的思考越多,上述两个问题似乎就越有问题。

我考虑过的另一个选择就是使一个Helper类进行一些相同的处理。 但这只能部分解决问题,因为某些相同的UI代码(引发属性更改的事件,XAML等)仍将同时存在于两个Views / ViewModels中。

最好的方法是什么? 有没有办法可以解决存储库/访问问题并进行UserControl? 还是不是我没有考虑过的基于接口或继承的替代方法?

编辑-要求输入代码。 给出一个全面的示例有点复杂,但这是每个VM的一个片段:

public void CheckOrderHist(int months)
{
    var endDate = DateTime.Today.AddMonths(months);
    Dictionary<OrderHistory, bool> orders = new Dictionary<OrderHistory, bool>();
    this.ordersToExclude.Clear();

    foreach (var kvp in rep.OrderHistories.GetRecent(months))
    {
        if (kvp.Key.MailingDate >= endDate)
        {
            orders.Add(kvp.Key, true);
            this.ordersToExclude.Add(((OrderHistory)kvp.Key).OrderID);
        }
        else
        {
            orders.Add(kvp.Key, false);
        }
    }

    BuildOrderExclusionsOnCount(); //code in this is near-identical across VM's too
    OrderHistoryMonths = Math.Abs(months); //OrderHistoryMonths is a property on the ViewModel
    OnPropertyChanged("MajorityOrderBoolean");
}

在另一个VM中:

private void CheckOrderHist(int months)
{
    var endDate = DateTime.Today.AddMonths(-months);
    ObservableCollection<Tuple<OrderHistory, bool>> orders = new ObservableCollection<Tuple<OrderHistory, bool>>();
    this.ordersToExclude.Clear();

    foreach (var tuple in rep.OrderHistories.GetRecent(-months))
    {
        if (tuple.Item1.MailingDate >= endDate)
        {
            orders.Add(new Tuple<OrderHistory,bool>(tuple.Item1, true));
            this.ordersToExclude.Add(tuple.Item1.OrderID);
        }
        else
        {
            orders.Add(new Tuple<OrderHistory, bool>(tuple.Item1, false));
        }
    }

    BuildOrderExclusionsOnCount(); //code in this is near-identical across VM's too
    OrderHistoryMonths = months; //OrderHistoryMonths is a property on the ViewModel
    OnPropertyChanged("OrderHistories");
    OnPropertyChanged("GroupedOrders");
}

这很好地说明了这个问题-函数本质上是相同的,但是一个使用了Dictionary,另一个使用了一个Tuple(没有充分的理由-它们都确实需要一个Tuple,以便于订购)。 一个任意取负的int参数,另一个取正数。

两者都包含不同的OnPropertyChanged事件,并且将使用存储库对象的不同副本,这使得很难使用Helper类正确地将它们分开。 但是,将其放入UserControl会将其与主ViewModel上的OrderHistoryMonths隔离。

如果我正确地听到了当前的评论,那么最好的解决方案是将主要的ForEach循环分配给帮助程序类,然后忍受其余的重复操作?

尽可能将公共逻辑提取到每个ViewModel可以构造的新“帮助程序”类中; 这是通过组合重复使用的标准模式。 您在问题中显示的代码是这种重构的理想选择。

就样板而言,这有点棘手。 这是通常很难解决的问题,必须逐案检查。 有多种方法可以简化属性更改通知,例如(封装属性更新,AOP等的辅助方法),但是这些通常是MVVM框架的一部分,并包含在整个应用程序范围内。 至于XAML复制,您通常可以使用样式,数据模板和值转换器来改进,但是再次,它需要仔细分析您的特定代码库以识别可能值得这种处理的模式。 如果您有更具体的示例,您认为这些示例很明显,但是不确定如何重构,那么这些示例可能会成为一个很好的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM