2012-06-12 5 views
6

Я изучаю WPF и MVVM на данный момент (или, по крайней мере, я пытаюсь ...).Изменение вида на Buttonclick

Я создал небольшое приложение-образец, в котором показано окно с двумя кнопками, каждое из которых должно показывать новый вид на клике. Поэтому я создал 3 UserControls (DecisonMaker с 2 кнопками и один Usercontrol для каждого «clicktarget»).

Так что я связала CotentControl из MainWindow в собственности под названием "CurrentView" в моем MainWindowViewModel

Код MainWindow.xaml:

<Window x:Class="WpfTestApplication.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfTestApplication" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <local:MainWindowViewModel /> 
</Window.DataContext> 
<Grid> 
    <ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> 
</Grid> 
</Window> 

Код MainWindowViewModel:

class MainWindowViewModel 
{  
    private UserControl _currentView = new DecisionMaker(); 
    public UserControl CurrentView 
    { 
     get { return _currentView; } 
     set { _currentView = value; } 
    } 

    public ICommand MausCommand 
    { 
     get { return new RelayCommand(LoadMouseView); } 
    } 

    public ICommand TouchCommand 
    { 
     get { return new RelayCommand(LoadTouchView); } 
    } 

    private void LoadMouseView() 
    { 
     CurrentView = new UserControlMouse(); 
    } 

    private void LoadTouchView() 
    { 
     CurrentView = new UserControlTouch(); 
    } 
} 

Первоначальный UserControl (DecisionMaker) отображается как предполагается. Также вызывается метод LoadMouseView. Но представление не меняется. Что мне не хватает?

ОБНОВЛЕНИЕ: Большое спасибо! Я пропустил интерфейс INotifyPropertyChanged. Все ваши ответы были просто замечательными и очень точными и полезными! Я не знаю, какой из них принять - Я думаю, что это самый справедливый способ принять «первый» ответ?

Я принял ответ blindmeis, поскольку он решил проблему и помог мне лучше понять MVVM. Но каждый ответ был действительно большим благодаря всем вам!

+1

ViewModel не должны иметь ссылку на вид/UserControl. поэтому вы должны удалить это из своей модели просмотра. это хорошая отправная точка: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx – blindmeis

ответ

6

Если вы хотите сделать mvvm - тогда у вас должно быть никаких ссылок на ваше мнение/пользовательское управление в вашей модели. вы должны реализовать INotifyPropertyChanged! ps: если вам нужно пространство имен System.Windows в вашей модели Viewmodel - тогда что-то не так.

в вашем случае, что вам нужно:

  • 1 mainviewmodel
  • 1 ViewModel для UserControlMouse
  • 1 ViewModel для UserControlTouch
  • 1 вид/UserControl для UserControlMouse
  • 1 вид/UserControl для UserControlTouch

ваш mainviewmodel должен иметь как минимум 2 команды для переключения вашего вида и 1 свойства для CurrentView. в вашей команде вы просто установите свой CurrentView в подходящий экземпляр viewmodel. по крайней мере вам понадобятся два набора данных для каждой модели просмотра, которые определяют правильный вид.

public object CurrentView 
{ 
    get { return _currentView; } 
    set { 
     _currentView = value; this.RaiseNotifyPropertyChanged("CurrentView");} 
} 

XAML

<Window x:Class="WpfTestApplication.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:WpfTestApplication" 
Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
<DataTemplate DataType="{x:Type local:MyMouseViewModel}"> 
    <local:MyMouseUserControlView/> 
    </DataTemplate> 
<DataTemplate DataType="{x:Type local:MyTouchViewModel}"> 
    <local:MyTouchUserControlView/> 
    </DataTemplate> 
</Window.Resources> 
<Window.DataContext> 
<local:MainWindowViewModel /> 
</Window.DataContext> 
<Grid> 

<!-- here your buttons with command binding, i'm too lazy to write this. --> 

<!-- you content control --> 
<ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> 
</Grid> 
</Window> 
+0

Это много помощи и информации для моего обучения. Я только вчера начал работу с WPF/MVVM, поэтому я уже был очень рад получить работу ICommand-Behavior;) – basti

+0

Если вы хотите чистый MVVM, то представление также не должно иметь ссылок на модель представления. Выполните запуск модели представления и просмотра при запуске приложения и привяжите модель представления к контексту данных в методе запуска. –

+0

+1 для «если вам нужно пространство имен System.Windows в вашей модели просмотра - тогда что-то не так». Я полностью согласен с этим; К сожалению, многие статьи и рамки MVVM рекомендуют выводить команды из «ICommand», которые вводят ненужную зависимость от сборок WPF в ViewModel. –

2

Для просмотра необходимо использовать INotifyPropertyChanged. В противном случае представление не будет уведомлено, когда свойство изменится в режиме просмотра.

class MainWindowViewModel : INotifyPropertyChanged 
{ 
    private UserControl _currentView = new DecisionMaker(); 

    public UserControl CurrentView 
    { 
     get { return _currentView; } 
     set 
     { 
      _currentView = value; 
      OnPropertyChanged("CurrentView"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
+0

Спасибо, что я реализовал это уже (после вашего ответа), и все работает отлично. Но зачем мне это здесь, а не для свойств типа String? – basti

+1

это работает на ваш случай, но его не mvvm – blindmeis

1

Вы должны реализовать INotifyPropertyChanged на MainWindowViewModel, так что вид информируется когда CurrentView свойство изменяется.

3

Я бы сделал что-то подобное, чтобы выбрать стиль ввода, который вы хотите, и MainWindow. Я добавил свойство, которое позволяет мне выбирать способ ввода.

public enum UserInterfaceModes 
{ 
    Mouse, 
    Touch, 
} 

public UserInterfaceModes UserInterfaceMode 
{ 
    get { return (UserInterfaceModes)GetValue(UserInterfaceModeProperty); } 
    set { SetValue(UserInterfaceModeProperty, value); } 
} 

public static readonly DependencyProperty UserInterfaceModeProperty = DependencyProperty.Register("UserInterfaceMode", typeof(UserInterfaceModes), typeof(MainWindow), new UIPropertyMetadata(UserInterfaceModes.Mouse)); 

затем для части просмотра xaml вы можете выбрать правильный шаблон с помощью триггера.

<Style TargetType="{x:Type local:MainWindow}"> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Mouse"> 
      <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type local:MainWindow}"> 
          <Grid Background="Red"/> 
         </ControlTemplate> 
        </Setter.Value> 
      </Setter> 
     </DataTrigger> 
     <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Touch"> 
      <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type local:MainWindow}"> 
          <Grid Background="Blue"/> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 
+0

Определенно отличный ответ, который поможет мне в будущем! Для этой конкретной проблемы, с которой я столкнулся сейчас, для тестирования/обучения, она не на 100% применима, поскольку она будет отрицать всю мою манеру кнопок;) Но в будущих «реальных» вариантах я обязательно вернусь к вашему коду! – basti

+0

Все, вы заставите меня покраснеть! : D – Andy

1

Это походит на поведение вы хотите довольно много, что вы получаете с [TabControl][1] - почему бы не использовать этот встроенный контроль и просто связать DataContext обеих вкладок одной и той же модели представления.

Это также имеет то преимущество, что ваша модель представления не будет знать о классах представления (я предполагаю, что UserControlMouse и т. Д. Являются элементами управления пользователя).

Примечание: это не применимо, если вам нужна модель просмотра, чтобы знать, находится ли она в касании или режиме мыши.

+0

Спасибо. Это общая цель здесь, чтобы разделить UserControl на Mouse- и TouchMode. Поэтому однажды во время начала мне нужно будет «знать» начальный пользовательский контроль. – basti

+0

@chiffre вы все равно не должны ссылаться на компоненты представления (пользовательские элементы управления) в модели представления, если хотите сделать MVVM –

+0

Думаю, что я буду следовать запросу blindmeis для будущей работы над ним. Спасибо за вашу большую помощь в этом случае! – basti

Смежные вопросы