2011-02-04 4 views
40

Я занимаюсь реорганизацией простого приложения для отслеживания MVVM, и мой вопрос заключается в том, как перенести событие SelectionChanged из моего кода в viewModel? Я рассмотрел некоторые примеры привязки элементов к командам, но не совсем понял это. Может ли кто-нибудь помочь с этим. Благодаря!WPF Связывание событий пользовательского интерфейса с командами в ViewModel

Может ли кто-нибудь предоставить решение, используя код ниже? Большое спасибо!

public partial class MyAppView : Window 
{ 
    public MyAppView() 
    { 
     InitializeComponent(); 

     this.DataContext = new MyAppViewModel(); 

     // Insert code required on object creation below this point. 
    } 

    private void contactsList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) 
    { 
     //TODO: Add event handler implementation here.   
     //for each selected contact get the labels and put in collection 

     ObservableCollection<AggregatedLabelModel> contactListLabels = new ObservableCollection<AggregatedLabelModel>(); 

     foreach (ContactListModel contactList in contactsList.SelectedItems) 
     { 
      foreach (AggregatedLabelModel aggLabel in contactList.AggLabels) 
      { 
       contactListLabels.Add(aggLabel); 
      } 
     } 
     //aggregate the contactListLabels by name 
     ListCollectionView selectedLabelsView = new ListCollectionView(contactListLabels); 

     selectedLabelsView.GroupDescriptions.Add(new PropertyGroupDescription("Name")); 
     tagsList.ItemsSource = selectedLabelsView.Groups; 
    } 
} 

ответ

83

Вы должны использовать EventTrigger в сочетании с InvokeCommandAction из пространства имен Windows.Interactivity. Вот пример:

<ListBox ...> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="SelectionChanged"> 
      <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"/> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</ListBox> 

Вы можете ссылаться System.Windows.Interactivity, перейдя Add reference > Assemblies > Extensions.

И полное пространство i: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity".

+0

Спасибо. Я новичок в программировании, так что простите меня - можете ли вы привести пример с помощью кода, который я предоставил? – Ben

+1

Вам нужно создать свойство команды в ViewModel под названием «SelectedItemChangedCommand». Commanding похож на события, но команда может иметь только одну функцию обратного вызова, в отличие от событий. Проверьте документы: http://msdn.microsoft.com/en-us/library/ms752308.aspx – Brian

+1

Если у вас нет Expression Blend, вам понадобится SDK: http://www.microsoft.com/downloads/ ru/details.aspx? FamilyID = D197F51A-DE07-4EDF-9CBA-1F1B4A22110D & displaylang = en – Murven

8

Этот вопрос имеет аналогичную проблему.

WPF MVVM : Commands are easy. How to Connect View and ViewModel with RoutedEvent

Как я справиться с этой проблемой, чтобы иметь свойство SelectedItem в ViewModel, а затем связать SelectedItem вашего ListBox или независимо от этого имущества.

+1

действительная точка, но не применима ко всем сценариям ... У меня есть сценарий, где я делаю то, что вы предлагаете, но также нужно использовать событие SelectionChanged – Jordan

0

Как @Cameron MacFarland упоминает, я бы просто двухсторонний привязывался к свойству viewModel. В настройщике свойств вы можете выполнять любую логику, например, добавлять в список контактов, в зависимости от ваших требований.

Однако, я бы не стал называть свойство SelectedTec, поскольку viewModel не должен знать о слое представления и о том, как он взаимодействует с его свойствами. Я бы назвал это что-то вроде CurrentContact или что-то в этом роде.

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

+1

Я не согласен что модель представления не должна знать о слое представления. Это, в конце концов, модель взгляда. Он не должен манипулировать объектами в представлении, но это только для того, чтобы он мог быть создан независимо от представления в модульных тестах. Я бы не назвал свойство 'SelectedItem', если коллекция модели представления не была названа' Items', но это другая проблема. –

+0

Посмотрите, что вы имеете в виду, но я склонен не воспринимать vm как «модель представления», скорее как адаптер, который не делает никаких предположений об пользовательском интерфейсе, а просто раскрывает его состояние и поведение с помощью команд и уведомлений. И это разделение не является «единственным» для модульных тестов, как вы говорите, но также означает, что пользовательский интерфейс может легко включаться и выходить и модифицироваться по мере необходимости и без необходимости изменения виртуальной машины. – HAdes

7

Чтобы реорганизовать этого вам нужно перенести свое мышление. Вы больше не будете обрабатывать событие с изменением выбора, а скорее сохраняете выбранный элемент в своей модели просмотра. Затем вы использовали бы двустороннюю привязку данных, так что когда пользователь будет выбирать элемент, ваша модель просмотра обновится, а когда вы измените выбранный элемент, ваше представление будет обновлено.

+0

Я думаю, что движущая часть мышления - это то место, где я изо всех сил стараюсь быть новичком-программистом! – Ben

1

я последую верхний ответ в этом question

В основном модели представления будет содержать список всех элементов и список выбранных элементов. Затем вы можете присоединить поведение к своему списку, который управляет вашим списком выбранных элементов.

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

<ListBox ItemsSource="{Binding AllItems}" Demo:SelectedItems.Items="{Binding SelectedItems}" SelectionMode="Multiple" /> 
2
<ListBox SelectionChanged="{eb:EventBinding Command=SelectedItemChangedCommand, CommandParameter=$e}"> 

</ListBox> 

Команда

{ЭБ: EventBinding} (Простой шаблон именования, чтобы найти Command)

{ЭБ: EventBinding Command = CommandName}

CommandParameter

$ е (EventAgrs)

$ это или $ this.Property

строка

https://github.com/JonghoL/EventBindingMarkup

1

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

Declare связывании поведение как:

public class PageChangedBehavior 
{ 
    #region Attached property 

    public static ICommand PageChangedCommand(DependencyObject obj) 
    { 
     return (ICommand)obj.GetValue(PageChangedCommandProperty); 
    } 
    public static void SetPageChangedCommand(DependencyObject obj, ICommand value) 
    { 
     obj.SetValue(PageChangedCommandProperty, value); 
    } 

    public static readonly DependencyProperty PageChangedCommandProperty = 
     DependencyProperty.RegisterAttached("PageChangedCommand", typeof(ICommand), typeof(PageChangedBehavior), 
      new PropertyMetadata(null, OnPageChanged)); 

    #endregion 

    #region Attached property handler 

    private static void OnPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var control = d as PageControl; 
     if (control != null) 
     { 
      if (e.NewValue != null) 
      { 
       control.PageChanged += PageControl_PageChanged; 
      } 
      else 
      { 
       control.PageChanged -= PageControl_PageChanged; 
      } 
     } 
    } 

    static void PageControl_PageChanged(object sender, int page) 
    { 
     ICommand command = PageChangedCommand(sender as DependencyObject); 

     if (command != null) 
     { 
      command.Execute(page); 
     } 
    } 

    #endregion 

}

А затем привязать его команда в XAML:

 <controls:PageControl 
      Grid.Row="2" 
      CurrentPage="{Binding Path=UsersSearchModel.Page,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
      PerPage="{Binding Path=UsersSearchModel.PageSize,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
      Count="{Binding Path=UsersSearchModel.SearchResults.TotalItemCount}" 
      behaviors:PageChangedBehavior.PageChangedCommand="{Binding PageChangedCommand}"> 
     </controls:PageControl> 
Смежные вопросы