Связывание команд с событиями? - PullRequest
12 голосов
/ 02 июня 2009

Какой хороший способ привязать команды к событиям? В моем приложении WPF есть события, которые я хотел бы записать и обработать с помощью моей модели представления, но я не уверен, как это сделать. Такие вещи, как потеря фокуса, наведение мыши, перемещение мыши и т. Д. Поскольку я пытаюсь придерживаться шаблона MVVM, мне интересно, есть ли чисто решение XAML.

Спасибо!

Ответы [ 6 ]

7 голосов
/ 06 июня 2009

Взгляните на прикрепленное командное поведение Марлона Греча , это может быть именно то, что вы ищете

5 голосов
/ 14 мая 2015

Использование System.Windows.Interactivity

…xmlns:i=http://schemas.microsoft.com/expression/2010/interactivity…

<Slider    
    <i:Interaction.Triggers>    
        <i:EventTrigger EventName="ValueChanged">
            <i:InvokeCommandAction    
                Command="{Binding MyCommand}"    
                CommandParameter="{Binding Text, ElementName=textBox}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Slider>

Убедитесь, что ваш проект ссылается на сборку System.Windows.Interactivity.

Источник: Блог MSDN Выполнение команды из события по вашему выбору

5 голосов
/ 02 июня 2009

Для обработки событий у вас должен быть некоторый код, который присоединяется к событию и выполняет вашу команду в ответ. Конечная цель - получить в XAML:

  MouseMoveCommand="{Binding MyCommand}"

Для этого вам нужно определить прикрепленное свойство для каждого события, которое вы хотите обработать. См. this для примера и основы для этого.

2 голосов
/ 07 октября 2011

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

public class EventBinding : DependencyObject
{
    public static string GetEventName(DependencyObject obj)
    {
        return (string)obj.GetValue(EventNameProperty);
    }

    public static void SetEventName(DependencyObject obj, string value)
    {
        obj.SetValue(EventNameProperty, value);
        var eventInfo = obj.GetType().GetEvent(value);
        var eventHandlerType = eventInfo.EventHandlerType;
        var eventHandlerMethod = typeof(EventBinding).
            GetMethod("EventHandlerMethod", BindingFlags.Static | BindingFlags.NonPublic);
        var eventHandlerParameters = eventHandlerType.GetMethod("Invoke").GetParameters();
        var eventArgsParameterType = eventHandlerParameters.
            Where(p => typeof(EventArgs).IsAssignableFrom(p.ParameterType)).
            Single().ParameterType;
        eventHandlerMethod = eventHandlerMethod.MakeGenericMethod(eventArgsParameterType);
        eventInfo.AddEventHandler(obj, Delegate.CreateDelegate(eventHandlerType, eventHandlerMethod));
    }

    private static void EventHandlerMethod<TEventArgs>(object sender, TEventArgs e)
        where TEventArgs : EventArgs
    {
        var command = GetCommand(sender as DependencyObject);
        command.Execute(new EventInfo<TEventArgs>(sender, e));
    }

    public static readonly DependencyProperty EventNameProperty = 
        DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventHandler));

    public static ICommand GetCommand(DependencyObject obj)
    {
        return (ICommand)obj.GetValue(CommandProperty);
    }

    public static void SetCommand(DependencyObject obj, ICommand value)
    {
        obj.SetValue(CommandProperty, value);
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventBinding));

}

public class EventInfo<TEventArgs>
{
    public object Sender { get; set; }
    public TEventArgs EventArgs { get; set; }

    public EventInfo(object sender, TEventArgs e)
    {
        Sender = sender;
        EventArgs = e;
    }
}

public class EventInfo : EventInfo<EventArgs>
{
    public EventInfo(object sender, EventArgs e)
        : base(sender, e) { }
}

public class EventBindingCommand<TEventArgs> : RelayCommand<EventInfo<TEventArgs>>
    where TEventArgs : EventArgs
{
    public EventBindingCommand(EventHandler<TEventArgs> handler)
        : base(info => handler(info.Sender, info.EventArgs)) { }
}

Примеры использования:

View

<DataGrid local:EventBinding.EventName="CellEditEnding"
          local:EventBinding.Command="{Binding CellEditEndingCommand}" />

Модель

private EventBindingCommand<DataGridCellEditEndingEventArgs> _cellEditEndingCommand;

public EventBindingCommand<DataGridCellEditEndingEventArgs> CellEditEndingCommand
{
    get 
    { 
        return _cellEditEndingCommand ?? (
            _cellEditEndingCommand = new EventBindingCommand<DataGridCellEditEndingEventArgs>(CellEditEndingHandler)); 
    }
}

public void CellEditEndingHandler(object sender, DataGridCellEditEndingEventArgs e)
{
    MessageBox.Show("Test");
}
0 голосов
/ 02 июня 2009

Выполнение команд, навигация по фреймам и делегирование команд поведение - довольно хороший шаблон. Он также может быть использован в Expression Blend.

Что касается "лучших практик", вы должны дважды подумать, прежде чем преобразовывать событие в команду. Обычно команда - это то, что пользователь делает намеренно, событие чаще всего является просто следом взаимодействия и не должно выходить за границы представления.

0 голосов
/ 02 июня 2009

Не думаю, что вы можете использовать его в чистом XAML, но взгляните на делегат команды .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...