2013-02-25 13 views
1

我正在構建一個使用大量相對複雜的列表視圖的WPF應用程序。我已經採用了列表視圖綁定到的集合的模式是View-Model對象的集合,而不是基礎模型對象的列表 - 我通過將數據綁定到完全獨立的列來填充代碼看起來有點像這樣可重複使用的ItemsControl(例如ListViews)+ MVVM

var itemsSource = messages.Select(i => new MessageViewModel(i)); 

在這種情況下,列表視圖顯示的是Message對象給用戶的列表。這工作正常,但相當笨重 - 特別是在處理收集更改事件時。

現在我想在其他地方在我的應用程序重複使用這個ListView控件以一致的方式來顯示消息的不同列表的用戶 - 我能看到的是

  • 選項創建一個列表觀點從ListView派生和數據綁定到類型MessageViewModel
  • 的集合創建databinds到Message對象的集合,要麼包含或結合到MessageViewModel
一些內部構造集合的列表視圖數據導出的控制

第一個選項要求大家誰使用該控件運行建立和維護MessageViewModel收集,第二個選項封裝此視圖模型集合的維護笨重的代碼,但意味着我需要重新實施ListView任何成員展示集合中的基礎項目,以便將它們轉換回原始的Message類型。

我有許多類似的列表視圖有類似的可重用性問題。

是否有更好的方法來處理基於WPF ItemsControl的視圖,這些視圖允許在MVVM應用程序中重用這些視圖?

+0

我無法理解您的問題。爲什麼你必須複製你的'ListView'?如果僅僅是一個樣式問題,你可以在共​​享資源字典中使用'Style'。或者如果你有一個'UserControl'和一個帶有一些代碼隱藏的'ListView',那麼你不應該對視圖模型有任何依賴關係,只要你像你說的那樣使用MVVM即可。也許你可以詳細闡述一下? – 2013-02-25 12:17:35

+0

@MartinLiversage這有助於澄清事情嗎?我嘗試創建一個完全封裝視圖模型創建過程(第二個選項)的列表視圖導致了很多重複「ListView」類成員的工作,這感覺不對,我真的很喜歡避免。 – Justin 2013-02-25 12:42:32

+0

選擇1聽起來不錯,但我不知道爲什麼你需要從列表視圖派生。如果您的數據模板的目標類爲主窗口資源或資源目錄中的類messageviewmodel,則wpf將根據您的數據模板格式化任何具有與其綁定的消息視圖模型集合的項目控件。您的數據模板可以在您的列表視圖中定義一個xaml包含用戶控件 – failedprogramming 2013-02-25 12:57:30

回答

1

在我看來,有要重用兩件事情:

  1. 暴露MessageViewModel的集合,這樣你就可以在此集合綁定到ListView的的ItemsSource。
  2. (可選)在特定的列表視圖上有一個樣式(或內容展示器或數據模板),您可以重複使用該樣式。這部分也可能包括後面的代碼,觸發器等。

你不應該混淆這兩者。

#2可以用您將應用於列表視圖或數據模板的樣式來實現。就個人而言,我喜歡將一個專用類定義爲MessageViewModel的集合,並在您的數據模板中將TargetType設置爲該類。

#1是實現Collection,INotifyCollecitonChanged和INotifyPropertyChanged的類。最好的方法(也是最簡單的)只是將其包裝在ObservableCollection中。在構建中,執行Select方法。然後有簿記的方法。

下面的一些示例(工作!)代碼。請注意,該視圖沒有代碼。我把兩個列表放在網格中兩次。 ContentControl和DataTemplate的使用是我的風格 - 有幾十種其他方式可以做到這一點。

======= Model.cs ====

using System; 

namespace SO 
{ 
    class Message 
    { 
     public string from { get; set; } 
     public string to { get; set; } 
     public string subject { get; set; } 
     public DateTime received { get; set; } 
    } 
} 

======= ViewModel.cs ====

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 

namespace SO 
{ 
    class MessageVM : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     private Message m_model; 

     public MessageVM(Message model) { 
      m_model = model; 
     } 

     private void raize(string prop) { 
      PropertyChanged(this, new PropertyChangedEventArgs("prop")); 
     } 

     public string from { 
      get { return m_model.from; } 
      set { m_model.from = value; raize("from"); } 
     } 

     public string to { 
      get { return m_model.to; } 
      set { m_model.subject = value; raize("to")); } 
     } 

     public string subject { 
      get { return m_model.subject; } 
      set { m_model.subject = value; raize("subject")); } 
     } 

     public DateTime received { 
      get { return m_model.received; } 
      set { m_model.received = value; raize("recieved")); } 
     } 

    } 

    class FolderVM : ObservableCollection<MessageVM> 
    { 
     public FolderVM(IEnumerable<Message> models) 
      :base(models.Select(msg => new MessageVM(msg))) 
     { 
     } 
    } 


    class SampleData 
    { 
     //static public FolderVM folder { get; set; } 

     static public FolderVM folder; 



     static SampleData() 
     { 
      // create a sample model 
      List<Message> model = new List<Message>(); 
      model.Add(new Message { from = "Bill", to = "Steve", subject = "Resusable Items Control", received = DateTime.Now.AddDays(-4) }); 
      model.Add(new Message { from = "Steve", to = "Bill", subject = "Resusable Items Control", received = DateTime.Now.AddDays(-3) }); 
      model.Add(new Message { from = "Bill", to = "Jeff", subject = "stack", received = DateTime.Now.AddDays(-2) }); 

      // initialize the view model 
      folder = new FolderVM(model); 
     } 
    } 
} 

==== === MainWindow.xaml ====

<Window x:Class="Paf.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:src="clr-namespace:SO" 
     Title="MainWindow" Height="350" Width="525" 
     > 

    <Window.Resources> 
     <DataTemplate DataType="{x:Type src:FolderVM}"> 
      <ListView ItemsSource="{Binding}"> 
       <ListView.View> 
        <GridView> 
         <GridViewColumn Header="from" Width="80" DisplayMemberBinding="{Binding Path=from}" /> 
         <GridViewColumn Header="to" Width="80" DisplayMemberBinding="{Binding Path=to}" /> 
         <GridViewColumn Header="subject" Width="200" DisplayMemberBinding="{Binding Path=subject}" /> 
         <GridViewColumn Header="received" Width="160" DisplayMemberBinding="{Binding Path=received}" /> 
        </GridView> 
       </ListView.View> 
      </ListView> 
     </DataTemplate>   
    </Window.Resources> 


    <StackPanel> 
     <ContentControl Content="{Binding Source={x:Static src:SampleData.folder}}" /> 
     <ContentControl Content="{Binding Source={x:Static src:SampleData.folder}}" /> 
    </StackPanel> 

</Window> 
相關問題