2011-03-08 33 views
6

Hãy xem xét rằng tôi có một ứng dụng chỉ xử lý MessagesUsers Tôi muốn Cửa sổ của tôi có một số Menu phổ biến và khu vực hiện tại View được hiển thị.Bao gồm xem một phần khi áp dụng mẫu thiết kế Mode-View-ViewModel

Tôi chỉ có thể làm việc với Tin nhắn hoặc Người dùng để tôi không thể làm việc đồng thời với cả hai Chế độ xem. Vì vậy, tôi có Controls sau

  • MessageView.xaml
  • UserView.xaml

Chỉ cần để làm cho nó dễ dàng hơn một chút, cả hai Message ModelUser Model trông như thế này:

  • Tên
  • Mô tả

Bây giờ, tôi có ba ViewModels sau:

  • MainWindowViewModel
  • UsersViewModel
  • MessagesViewModel

Các UsersViewModelMessagesViewModel cả chỉ cần lấy một ObserverableCollection<T> của liên quan đến nó Model bị ràng buộc trongtương ứngnhư thế này:

<DataGrid ItemSource="{Binding ModelCollection}" />

Các MainWindowViewModel móc lên hai khác nhau Commands rằng đã thực hiện ICommand trông giống như sau:

public class ShowMessagesCommand : ICommand 
{ 
    private ViewModelBase ViewModel { get; set; } 
    public ShowMessagesCommand (ViewModelBase viewModel) 
    { 
     ViewModel = viewModel; 
    } 
    public void Execute(object parameter) 
    { 
     var viewModel = new ProductsViewModel(); 
     ViewModel.PartialViewModel = new MessageView { DataContext = viewModel }; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public event EventHandler CanExecuteChanged; 
} 

Và có nhau một như nó sẽ hiển thị người dùng . Bây giờ này giới thiệu ViewModelBase mà chỉ nắm giữ sau:

tài sản
public UIElement PartialViewModel 
    { 
     get { return (UIElement)GetValue(PartialViewModelProperty); } 
     set { SetValue(PartialViewModelProperty, value); } 
    } 

    public static readonly DependencyProperty PartialViewModelProperty = 
     DependencyProperty.Register("PartialViewModel", typeof(UIElement), typeof(ViewModelBase), new UIPropertyMetadata(null)); 

sự phụ thuộc này được sử dụng trong MainWindow.xaml để hiển thị User Control dynamicly như thế này:

<UserControl Content="{Binding PartialViewModel}" />

Ngoài ra còn hai nút trên Window này kích hoạt các Lệnh:

  • ShowMessagesCommand
  • ShowUsersCommand

Và khi chúng được bắn, những thay đổi UserControl vì PartialViewModel là một tài sản phụ thuộc.

Tôi muốn biết nếu đây là thực tiễn không tốt? Tôi có nên không tiêm Điều khiển người dùng như thế này không? Có cách nào khác "tốt hơn" thay thế tương ứng tốt hơn với mẫu thiết kế? Hoặc đây có phải là cách hay để bao gồm một phần lượt xem không?

Trả lời

2

tại sao không sử dụng ContentPresenter/ContentControl bằng bảng dữ liệu trong mainwindow của bạn?

thay vì UserControl Content = "{Binding PartialViewModel}" />, bạn có thể sử dụng một:

<ContentPresenter Content="{Binding Path=PartialViewModel}" /> 

tất cả các bạn phải làm: được thiết lập PartialViewmodel của bạn để viewmodel con quý vị và tạo ra một datatemplate, vì vậy WPF sẽ biết làm thế nào để render childviewmodel bạn

<DataTemplate DataType={x:Type UserViewModel}> 
    <UserView/> 
</DataTemplate> 

<DataTemplate DataType={x:Type MessageViewModel}> 
    <MessageView/> 
</DataTemplate> 

khi đã bao giờ bạn thiết PartialViewmodel của bạn trong MainViewmodel của bạn, quyền View sẽ render trong ContenControl của bạn.

Chỉnh sửa 1 ít nhất bạn phải triển khai INotifyPropertyChanged trong ViewModel của bạn và kích hoạt nó khi nào thuộc tính PartViewModel được đặt.

Chỉnh sửa 2 nếu bạn sử dụng Lệnh trong dạng xem của bạn sẽ xem xét một số triển khai khung mvvm như DelegateCommand hoặc RelayCommand. xử lý ICommand trở nên dễ dàng hơn nhiều với điều này. trong mainviewmodel của mình, bạn có thể tạo các lệnh đơn giản như vậy

private DelegateCommand _showMessageCommand; 
public ICommand ShowMessageCommand 
{ 
    get 
    { 
     return this._showMessageCommand ?? (this._showMessageCommand = new DelegateCommand(this.ShowMessageExecute, this.CanShowMessageExecute)); 
     } 
    } 
+0

Thật tuyệt, tôi thích điều đó. –

+0

Nhân tiện, có vấn đề gì khi sử dụng phương pháp này thay thế không? Điều gì sẽ là lợi ích từ việc sử dụng một khung MVVM thay vào đó? –

+0

bạn có thể sử dụng bất kỳ khung mvvm nào và giải pháp này hoặc bạn có thể sử dụng bất kỳ khung công cụ mvvm nào và không phải giải pháp này;) nó không phụ thuộc lẫn nhau. có một vài giải pháp cách bạn có được chế độ xem của mình cho chế độ xem của bạn và ngược lại. cái này ở đây là một wpf đơn giản được xây dựng trong – blindmeis

0

bạn nên xem prism. Nó cung cấp cho bạn khu vực xử lý. Tôi cũng sẽ xem xét MEF để Xuất Chế độ xem và theo cách này duy trì khả năng mở rộng cho dự án của bạn.

1

Tôi sẽ xem xét việc sử dụng khung MVVM chẳng hạn như Caliburn.Micro làm cho chế độ xem cực kỳ dễ dàng. Nếu bạn có thuộc tính trên mô hình chế độ xem của mình là loại kiểu xem và ContentControl trên chế độ xem của bạn được đặt tên giống như thuộc tính của bạn, thì Caliburn.Micro sẽ định vị chế độ xem mô hình xem tương ứng qua quy ước, thực hiện việc ràng buộc cho bạn tự động và chèn chế độ xem vào ContentControl.

Tôi cũng sẽ tránh sử dụng thuộc tính phụ thuộc trên các kiểu xem của bạn và thay vào đó hãy triển khai INotifyPropertyChanged. Caliburn.Micro đi kèm với một loại PropertyChangedBase thực hiện giao diện này, và cũng cung cấp một phương thức trợ giúp để gọi sự kiện PropertyChanged sử dụng các biểu thức lambda chứ không phải các chuỗi ma thuật (tốt hơn cho việc tái cấu trúc sau này).

EDIT

http://msdn.microsoft.com/en-us/library/ms743695.aspx cho thấy một ví dụ về triển khai thực hiện INotifyPropertyChanged.

Để đạt được những gì bạn muốn làm trong Caliburn.Micro, bạn sẽ làm điều gì đó như sau (một ví dụ thô, nhưng nó chỉ cho bạn cách dễ dàng nó đang làm xem phần sử dụng một khuôn khổ MVVM):

public class MainViewModel : Conductor<IScreen>.Collection.OneActive 
{ 
    private UsersViewModel usersViewModel; 

    private MessagesViewModel messagesViewModel; 

    public UsersViewModel UsersViewModel 
    { 
    get { return this.usersViewModel; } 
    set { this.usersViewModel = value; this.NotifyOfPropertyChanged(() => this.UsersViewModel); 
    } 

    public MessagesViewModel MessagesViewModel 
    { 
    get { return this.messagesViewModel; } 
    set { this.messagesViewModel = value; this.NotifyOfPropertyChanged(() => this.MessagesViewModel); 
    } 

    public MainViewModel() 
    { 
    this.UsersViewModel = new UsersViewModel(); 
    this.MessagesViewModel = new MessagesViewModel(); 

    this.Items.Add(this.UsersViewModel); 
    this.Items.Add(this.MessagesViewModel); 

    // set default view 
    this.ActivateItem(this.UsersViewModel); 
    } 

    public ShowUsers() 
    { 
    this.ActivateItem(this.UsersViewModel); 
    } 

    public ShowMessages() 
    { 
    this.ActivateItem(this.MessagesViewModel);  
    } 
} 

Lưu ý rằng UsersViewModelMessagesViewModel sẽ lấy được từ Screen.

Để gọi các động từ ShowUsers hoặc ShowMessages bằng Caliburn.Micro, bạn chỉ cần tạo các điều khiển chế độ xem có cùng tên. Loại dây dẫn có thuộc tính ActiveItem là mục hiện đang được tiến hành, vì vậy bạn có thể thêm ContentControl vào MainView.xaml có tên ActiveItem và Caliburn.Micro sẽ xử lý việc chèn chế độ xem chính xác.

Vì vậy MainView.xaml của bạn có thể trông giống như:

<Grid> 
    <Grid.ColumnDefinitions> 
    <ColumnDefinition Width="200" /> 
    <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinition> 

    <!-- Menu in left hand column --> 
    <StackPanel Grid.Column="0"> 
    <Button x:Name="ShowUsers">Show Users</Button> 
    <Button x:Name="ShowMessages">Show Messages</Button> 
    </StackPanel> 

    <!-- Currently active item --> 
    <ContentControl x:Name="ActiveItem" Grid.Column="1" /> 
</Grid> 
+0

Bạn có thể thêm ví dụ về cách bạn sử dụng INotifyPropertyChanged thay thế nếu Thuộc tính phụ thuộc không? –

+0

Ví dụ được thêm vào câu trả lời – devdigital

2

Đây không phải là một cách tiếp cận xấu ngay từ cái nhìn đầu tiên, nó có thể là tốt để sử dụng trong một ứng dụng nhỏ.

Tuy nhiên, có một vài điều mà không phải là đẹp:

  1. ViewModelBase cần phải được một DependencyObject để có một DependencyProperty. Trong thế giới thực, tôi đã thấy rằng nó rất khó chịu khi phải đối xử với ViewModels theo cách đơn luồng (có rất nhiều hoạt động không đồng bộ mà người ta có thể muốn thực hiện).
  2. Nó không mở rộng quy mô; việc thay đổi bố cục sẽ yêu cầu một lượng đáng kể công việc.

Bất kỳ khung MVVM phong phú nào giúp dễ dàng tạo thành giao diện người dùng bằng cách cung cấp cơ sở hạ tầng để soạn các Lượt xem phụ vào Chế độ xem chính của bạn. Trong Prism (đó là sở thích cá nhân của tôi), điều này xảy ra với Regions.

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