Подтвердить что ты не робот

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;
    }
}
4b9b3361

Ответ 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".

Ответ 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>