Привязка события WPF к ViewModel (для Некомандных классов)
Я работаю над второй версией приложения, и как часть перезаписи я должен перейти к архитектуре MVVM. Я получаю давление, чтобы поставить абсолютно каждый бит кода в классе view model-наличие c# в коде за файлом не одобряется. (Знаю, знаю...Я понимаю, что код позади не плохая вещь, но на этот раз это не мой звонок).
для объектов, которые реализуют командный интерфейс, это легко. Я смог найти тонну информации о том, как чтобы привязать команду этих объектов к ICommand в модели представления. Проблема заключается в объектах, которые не имеют этого интерфейса, например
<ListBox
x:Name="myListBox"
MouseDoubleClick="myCallbackFunction">
<!-- ... -->
</ListBox>
Я хочу знать, как привязать событие MouseDoubleClick для Listbox к myCallbackFunction, которое реализовано в модели представления. Это вообще возможно?
спасибо!
4 ответов
это напрямую невозможно. Это можно сделать с помощью вложенного свойства или поведения, хотя все равно было бы немного сложно найти и вызвать соответствующий метод (это можно сделать с помощью отражения довольно легко).
это, как говорится, обычно обрабатывается через ICommand
- например, MVVM Light имеет отличный EventToCommand поведение для сопоставления любого события с ICommand на ViewModel. Преимущество использования ICommand заключается в том, что вы все еще можете использовать Привязка данных, так как ICommand предоставляется как свойство.
чтобы напрямую ответить на ваш вопрос, пожалуйста, обратитесь к почему избежать codebehind в шаблоне WPF MVVM? это предполагает две возможные вещи, которые вы хотите.
однако, почему вы хотите привязать MouseDoubleClick списка к вашей ICommand в viewmodel?
альтернативный способ заключается в том, что вы пишете метод в codebehind для регистрации MouseDoubleClick. Это не плохо, из-за фактов следующий.
значимая привязка данных-это взаимодействие между представлением и viewmodel. Например, когда пользователь вводит текст в текстовое поле, viewmodel также обновляется. Напротив, если viewmodel получает данные из базы данных, они будут отображаться в представлении. Однако это не тот случай, когда ICommand в вашей viewmodel привязывается к представлению.
конечно, CanExcute ICommand будет важен для вашей viewmodel, но в во многих случаях это не связано с viewmodel или не касается. В этом случае разница между привязкой ICommand и записью codebehind заключается в том, что событие MouseDoubleClick связывается с ICommand или регистрируется обработчиком событий.
WPF поддерживает расширения разметки для событий с .NET 4.5. Используя эту возможность, я реализовал невероятно универсальный метод расширения привязки и написал об этом здесь:
http://www.singulink.com/CodeIndex/post/building-the-ultimate-wpf-event-method-binding-extension
может использоваться для привязки к методу с использованием полного синтаксиса пути свойства, поддерживает привязки и другие расширения разметки в качестве аргументов и автоматически направляет к методу, который соответствует подписи предоставленных аргументов. Вот несколько примеров использования:
<!-- Basic usage -->
<Button Click="{data:MethodBinding OpenFromFile}" Content="Open" />
<!-- Pass in a binding as a method argument -->
<Button Click="{data:MethodBinding Save, {Binding CurrentItem}}" Content="Save" />
<!-- Another example of a binding, but this time to a property on another element -->
<ComboBox x:Name="ExistingItems" ItemsSource="{Binding ExistingItems}" />
<Button Click="{data:MethodBinding Edit, {Binding SelectedItem, ElementName=ExistingItems}}" />
<!-- Pass in a hard-coded method argument, XAML string automatically converted to the proper type -->
<ToggleButton Checked="{data:MethodBinding SetWebServiceState, True}"
Content="Web Service"
Unchecked="{data:MethodBinding SetWebServiceState, False}" />
<!-- Pass in sender, and match method signature automatically -->
<Canvas PreviewMouseDown="{data:MethodBinding SetCurrentElement, {data:EventSender}, ThrowOnMethodMissing=False}">
<controls:DesignerElementTypeA />
<controls:DesignerElementTypeB />
<controls:DesignerElementTypeC />
</Canvas>
<!-- Pass in EventArgs -->
<Canvas MouseDown="{data:MethodBinding StartDrawing, {data:EventArgs}}"
MouseMove="{data:MethodBinding AddDrawingPoint, {data:EventArgs}}"
MouseUp="{data:MethodBinding EndDrawing, {data:EventArgs}}" />
<!-- Support binding to methods further in a property path -->
<Button Content="SaveDocument" Click="{data:MethodBinding CurrentDocument.DocumentService.Save, {Binding CurrentDocument}}" />
просмотр сигнатур метода модели:
public void OpenFromFile();
public void Save(DocumentModel model);
public void Edit(DocumentModel model);
public void SetWebServiceState(bool state);
public void SetCurrentElement(DesignerElementTypeA element);
public void SetCurrentElement(DesignerElementTypeB element);
public void SetCurrentElement(DesignerElementTypeC element);
public void StartDrawing(MouseEventArgs e);
public void AddDrawingPoint(MouseEventArgs e);
public void EndDrawing(MouseEventArgs e);
public class Document
{
// Fetches the document service for handling this document
public DocumentService DocumentService { get; }
}
public class DocumentService
{
public void Save(Document document);
}