WPF привязка событий пользовательского интерфейса к командам в ViewModel
Я делаю несколько рефакторинга простого приложения, чтобы следовать MVVM, и мой вопрос заключается в том, как перенести событие SelectionChanged из моего кода в viewModel? Ive рассмотрел некоторые примеры привязки элементов к командам, но не понял этого. Может ли кто-нибудь помочь с этим. Спасибо!
Может ли кто-нибудь предоставить решение, используя код ниже? Большое спасибо!
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;
}
}
Ответы
Ответ 1
Вы должны использовать EventTrigger
в сочетании с InvokeCommandAction
из пространства имен Windows. Вот пример:
<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"
.
Ответ 2
Этот вопрос имеет аналогичную проблему.
WPF MVVM: Команды просты. Как подключить View и ViewModel с помощью RoutedEvent
Способ, которым я решаю эту проблему, - иметь свойство SelectedItem в ViewModel, а затем привязать SelectedItem вашего ListBox или что-то еще к этому свойству.
Ответ 3
Лучше всего использовать Windows.Interactivity
. Используйте EventTriggers
для присоединения ICommand
к любому RoutedEvent
.
Вот статья, чтобы вы начали: Поведение и триггеры Silverlight и WPF
Ответ 4
Чтобы реорганизовать это, вам нужно переложить свое мышление. Вы больше не будете обрабатывать событие с изменением выбора, а скорее сохраняете выбранный элемент в своей модели просмотра. Затем вы использовали бы двустороннюю привязку данных, чтобы при выборе пользователем элемента, ваша модель просмотра обновляется, а когда вы меняете выбранный элемент, ваше представление обновляется.
Ответ 5
<ListBox SelectionChanged="{eb:EventBinding Command=SelectedItemChangedCommand, CommandParameter=$e}">
</ListBox>
Команда
{eb: EventBinding} (Простой шаблон именования для поиска команды)
{eb: EventBinding Command = CommandName}
CommandParameter
$e (EventAgrs)
$this или $this.Property
строка
https://github.com/JonghoL/EventBindingMarkup
Ответ 6
Я бы ответил на главный ответ в этом question
В основном ваша модель просмотра будет содержать список всех ваших элементов и список выбранных элементов. Затем вы можете присоединить поведение к своему списку, который управляет вашим списком выбранных элементов.
Выполнение этого означает, что у вас ничего нет в коде, и xaml довольно легко следовать, а также поведение может быть повторно использовано в другом месте вашего приложения.
<ListBox ItemsSource="{Binding AllItems}" Demo:SelectedItems.Items="{Binding SelectedItems}" SelectionMode="Multiple" />
Ответ 7
Иногда решение события привязки для команды через триггер Interactivity не работает, когда необходимо связать событие пользовательского usercontrol.
В этом случае вы можете использовать пользовательское поведение.
Объявить поведение привязки как:
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>
Ответ 8
Как упоминает @Cameron MacFarland, я бы просто привязал свойство к объекту viewModel в двух направлениях. В настройщике свойств вы можете выполнять любую логику, например, добавлять в список контактов, в зависимости от ваших требований.
Однако я бы не обязательно вызывал свойство "SelectedItem", поскольку viewModel не должен знать о слое представления и как он взаимодействует с его свойствами. Я бы назвал это что-то вроде CurrentContact или что-то в этом роде.
Очевидно, что это только если вы просто не хотите создавать команды как упражнение для практики и т.д.
Ответ 9
Рассмотрим Microsoft.Xaml.Behaviors.Wpf, его владельцем является Microsoft
которую вы можете увидеть на этой странице.
Владелец System.Windows.Interactivity.WPF - mthamil
, кто-нибудь может сказать мне, надежно ли это?
Пример Microsoft.Xaml.Behaviors.Wpf
:
<UserControl ...
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
...>
<Button x:Name="button">
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="Click" SourceObject="{Binding ElementName=button}">
<behaviors:InvokeCommandAction Command="{Binding ClickCommand}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</Button>
</UserControl>