簡體   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