在我看來,有要重用兩件事情:
- 暴露MessageViewModel的集合,這樣你就可以在此集合綁定到ListView的的ItemsSource。
- (可選)在特定的列表視圖上有一個樣式(或內容展示器或數據模板),您可以重複使用該樣式。這部分也可能包括後面的代碼,觸發器等。
你不應該混淆這兩者。
#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>
來源
2013-02-25 18:43:03
Uri
我無法理解您的問題。爲什麼你必須複製你的'ListView'?如果僅僅是一個樣式問題,你可以在共享資源字典中使用'Style'。或者如果你有一個'UserControl'和一個帶有一些代碼隱藏的'ListView',那麼你不應該對視圖模型有任何依賴關係,只要你像你說的那樣使用MVVM即可。也許你可以詳細闡述一下? – 2013-02-25 12:17:35
@MartinLiversage這有助於澄清事情嗎?我嘗試創建一個完全封裝視圖模型創建過程(第二個選項)的列表視圖導致了很多重複「ListView」類成員的工作,這感覺不對,我真的很喜歡避免。 – Justin 2013-02-25 12:42:32
選擇1聽起來不錯,但我不知道爲什麼你需要從列表視圖派生。如果您的數據模板的目標類爲主窗口資源或資源目錄中的類messageviewmodel,則wpf將根據您的數據模板格式化任何具有與其綁定的消息視圖模型集合的項目控件。您的數據模板可以在您的列表視圖中定義一個xaml包含用戶控件 – failedprogramming 2013-02-25 12:57:30