2010-01-01 30 views
14

Gần đây tôi đã bắt đầu điều tra mẫu MVVM với WPF cho một dự án sắp tới. Tôi bắt đầu với Josh Smith's MSDN article. Tôi có một câu hỏi (rất nhiều, nhưng hãy bắt đầu bằng một câu hỏi):MVVM (với WPF) - Liên kết nhiều chế độ xem với cùng ViewModel

Tôi có một IndividualViewModel hiển thị các đặc tính của mô hình. Tôi cần hai chế độ xem "Thêm cá nhân" và "Chỉnh sửa cá nhân" rất giống như bạn có thể tưởng tượng. Những gì tôi đã làm hiện nay là có 2 lớp con AddIndividualViewModel và EditIndividualViewModel để hiển thị các lệnh Add và Edit tương ứng. Tôi cũng có 2 chế độ xem có tên similary có liên kết với chúng.

Bây giờ phương thức này hoạt động và các lớp này khá nhỏ, nhưng tôi tự hỏi liệu tôi có thể chỉ có một mô hình xem, hiển thị cả hai lệnh. Tôi vẫn sẽ có 2 chế độ xem sẽ liên kết với cùng một kiểu xem này, hiển thị lệnh thích hợp dưới dạng nút. Tôi không chắc chắn làm thế nào để làm điều này. Trong các nguồn lực cửa sổ chính tôi có cái gì đó như:

 <DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}"> 
      <Views:AddIndividualView /> 
     </DataTemplate> 

Với phương pháp này bắt buộc bạn chỉ có thể có một one-to-one ràng buộc, ví dụ: quan điểm tương tự luôn được hiển thị cho một mô hình điểm nhất định. Có cách nào để tự động chuyển chế độ xem tùy thuộc vào thuộc tính trên mô hình chế độ xem (ví dụ: IndividualViewModel.Mode) hay không. Có cách tiếp cận khác mà tôi nên cân nhắc không?

Lưu ý rằng cửa sổ chính có bộ sưu tập các kiểu xem và hiển thị từng mô hình trong tab.

Cảm ơn bạn!

Trả lời

1

Không có lý do gì khiến bạn không thể đạt được điều đó. Một cách để làm điều này là cung cấp một số cờ trong mô hình xem của bạn cho biết bạn đang ở chế độ thêm hay trong chế độ chỉnh sửa và tạo kiểu xem của bạn dựa trên lá cờ đó bằng cách sử dụng các ràng buộc đơn giản, trình kích hoạt hoặc bộ chọn mẫu.

Để tham khảo, bạn có thể xem Sacha Barber's DataWrapper class là một phần trong khuôn khổ Cinch của mình (không áp dụng trực tiếp cho trường hợp của bạn, nhưng đó là điểm khởi đầu tốt) bao bọc các trường dữ liệu trong mô hình xem theo cách hỗ trợ cờ để chuyển đổi giữa chỉ đọc (chế độ xem bản ghi) và đọc-ghi (chế độ chỉnh sửa bản ghi). Bạn có thể áp dụng cách tiếp cận tương tự để tạo sự khác biệt giữa thêm và chỉnh sửa.

Về cơ bản, thay vì có các thuộc tính đơn giản trong mô hình chế độ xem của bạn, hãy khởi tạo lớp trình bao bọc dữ liệu bao gồm thuộc tính Value và thuộc tính IsAdding. Theo quan điểm của bạn, bạn có thể sử dụng các ràng buộc, trình kích hoạt hoặc bộ chọn mẫu để sửa đổi các mẫu dựa trên thuộc tính đó.

4

Cảm ơn bạn đã chỉ cho tôi đúng hướng! Tôi vẫn còn mới với WPF quá và tìm hiểu về tất cả các khả năng khác nhau bao gồm cả phương pháp ràng buộc. Dù sao cho bất cứ ai quan tâm, đây là giải pháp mà tôi đã đến cho trường hợp cụ thể này:

Tôi quyết định giữ các mô hình xem được phân tách trong hai lớp con AddIndividualViewModel và EditIndividualViewModel chỉ hiển thị các lệnh, thay vì cố gắng quản lý trạng thái trong một lớp. Tuy nhiên tôi muốn có một cái nhìn để tôi không nhân đôi XAML.Tôi đã kết thúc bằng hai DataTemplates và DataTemplateSelector để chuyển ra các nút hành động tùy thuộc vào mô hình điểm:

 <DataTemplate x:Key="addTemplate"> 
      <Button Command="{Binding Path=AddCommand}">Add</Button> 
     </DataTemplate> 

     <DataTemplate x:Key="editTemplate"> 
      <Button Command="{Binding Path=UpdateCommand}">Update</Button> 
     </DataTemplate> 

     <TemplateSelectors:AddEditTemplateSelector 
      AddTemplate="{StaticResource addTemplate}" 
      EditTemplate="{StaticResource editTemplate}" 
      x:Key="addEditTemplateSelector" /> 

và một người dẫn chương trình nội dung ở phía dưới có dạng:

 <ContentPresenter Content="{Binding}" 
          ContentTemplateSelector="{StaticResource addEditTemplateSelector}" /> 

Đây là mã cho bộ chọn mẫu:

class AddEditTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate AddTemplate { get; set; } 
    public DataTemplate EditTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is AddIndividualViewModel) 
     { 
      return AddTemplate; 
     } 
     else if (item is EditIndividualViewModel) 
     { 
      return EditTemplate; 
     } 

     return null; 
    } 
} 

Điều này có thể hoặc không thể thực hiện điều cuối cùng (đã đưa ra yêu cầu) nhưng tốt nhất là tôi có tùy chọn này.

1

Đối với tác vụ này, bạn không cần bất kỳ DataTemplateSelector nào cả.

  1. Xuất phát cả EditIndividualVM và AddINdividualVM từ IndividualVM.
  2. Tuyến đường Chỉnh sửa và AddCommands đến thuộc tính setter trong IndividualVM.
  3. Máy ảo setter = new AddIndividualVM hoặc VM = new EditIndividualVM tùy thuộc vào nút nào được nhấn.
  4. Trong XAML bạn ràng buộc trong contentgrid đến tài sản ảo của bạn như thế này:

+2

Dường như bạn có mã bị thiếu. Bạn có thể cập nhật câu trả lời của mình với đoạn mã không? – PlagueHammer

4

Vì vậy, bạn cần 2 quan điểm khác nhau dựa trên một giá trị bất động sản. Một điều cần xem xét là refactor your presentation code, vì vậy thay vì giá trị của thuộc tính bạn có thể có các lớp con thực. Sau đó, bạn có thể sử dụng 2 khác nhau DataTemplate cho mỗi lớp.

<DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}"> 
    <Views:AddIndividualView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type ViewModels:EditIndividualViewModel}"> 
    <Views:EditIndividualView /> 
</DataTemplate> 

Nếu bạn cho rằng đó là quá mức cần thiết, bạn có thể sử dụng trình kích hoạt và đặt chế độ xem cụ thể vào ContentPresenter.

<DataTemplate x:Key="AddIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <Views:AddIndividualView /> 
</DataTemplate> 

<DataTemplate x:Key="EditIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <Views:EditIndividualView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <ContentPresenter Content="{Binding}"> 
    <ContentPresenter.Style> 
     <Style TargetType="ContentPresenter"> 
     <Setter Property="ContentTemplate" Value="{StaticResource AddIndividualTemplate}" /> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding Mode}" Value="{x:Static ViewModels:IndividualMode.Edit}"> 
      <Setter Property="ContentTemplate" Value="{StaticResource EditIndividualTemplate}" /> 
      </DataTrigger> 
     </Style.Triggers> 
     </Style> 
    </ContentPresenter.Style> 
    </ContentPresenter> 
</DataTemplate> 
+0

Đây là giải pháp MVVM cổ điển. Nó chỉ định cả hai tùy chọn và không có mã phía sau. –

Các vấn đề liên quan