2011-10-25 2 views
9

Я пытаюсь отобразить окно входа в систему после загрузки MainWindow, придерживаясь шаблона MVVM. Поэтому я пытаюсь привязать мои главные окна Loaded event к событию в моей модели viewmodel. Вот что я пробовал:Привязка загруженного события?

MainWindowView.xaml

<Window x:Class="ScrumManagementClient.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" 
     DataContext="ViewModel.MainWindowViewModel" 
     Loaded="{Binding ShowLogInWindow}"> 
    <Grid> 

    </Grid> 
</Window> 

MainWindowViewModel.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ScrumManagementClient.ViewModel 
{ 
    class MainWindowViewModel : ViewModelBase 
    { 
     public void ShowLogInWindow(object sender, EventArgs e) 
     { 
      int i = 0; 
     } 
    } 
} 

Сообщение об ошибке я получаю "Loaded =" {Binding ShowLogInWindow}»не valid. '{Binding ShowLogInWindow}' не является допустимым именем метода обработчика события. Только методы экземпляра в сгенерированном или закодированном классе действительны. "

ответ

21

Вам понадобится использовать dll System.Windows.Interactivity.

Затем добавить пространство имен в вашем XAML:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

Затем вы можете сделать такие вещи, как:

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="Loaded"> 
     <i:InvokeCommandAction Command="{Binding MyICommandThatShouldHandleLoaded}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

Пожалуйста, обратите внимание, что вам придется использовать ICommand (или DelegateCommand это использовать Prism , или RelayCommand, если вы используете MVVMLight), а DataContext вашего окна должен содержать эту ICommand.

+4

Осторожно. System.Windows.Interactivity не входит в дистрибутив .NET. – Kugel

+1

Вы можете найти это на законных основаниях в Интернете, я считаю, что это часть пакета Blend. –

+0

спасибо за помощь, которую я начинаю куда-то забирать, эксплоит поражает мою ICommand, но не входит в разделы get {} или set {}, любая идея как это исправить? –

8

Использование прилагаемого поведения. Это допускается в MVVM ....

(код ниже, может/не может скомпилировать так же, как это)

XAML ...

<Window x:Class="..." 
      ... 
      xmlns:local="... namespace of the attached behavior class ..." 
      local:MyAttachedBehaviors.LoadedCommand="{Binding ShowLogInWindowCommand}"> 
    <Grid> 
    </Grid> 
    </Window> 

Код За ...

class MainWindowViewModel : ViewModelBase 
    { 
     private ICommand _showLogInWindowCommand; 

     public ICommand ShowLogInWindowCommand 
     { 
     get 
     { 
       if (_showLogInWindowCommand == null) 
       { 
        _showLogInWindowCommand = new DelegateCommand(OnLoaded) 
       } 
       return _showLogInWindowCommand; 
     } 
     } 

     private void OnLoaded() 
     { 
      //// Put all your code here.... 
     } 
    } 

И прикрепленное поведение ...

public static class MyAttachedBehaviors 
    { 
     public static DependencyProperty LoadedCommandProperty 
     = DependencyProperty.RegisterAttached(
      "LoadedCommand", 
      typeof(ICommand), 
      typeof(MyAttachedBehaviors), 
      new PropertyMetadata(null, OnLoadedCommandChanged)); 

     private static void OnLoadedCommandChanged 
      (DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
     { 
      var frameworkElement = depObj as FrameworkElement; 
      if (frameworkElement != null && e.NewValue is ICommand) 
      { 
       frameworkElement.Loaded 
       += (o, args) => 
        { 
         (e.NewValue as ICommand).Execute(null); 
        }; 
      } 
     } 

     public static ICommand GetLoadedCommand(DependencyObject depObj) 
     { 
     return (ICommand)depObj.GetValue(LoadedCommandProperty); 
     } 

     public static void SetLoadedCommand(
      DependencyObject depObj, 
      ICommand value) 
     { 
     depObj.SetValue(LoadedCommandProperty, value); 
     } 
    } 

DelegateCommand исходный код можно найти в интернете ... Его наиболее подходит ICommand API для MVVM.

редактировать: 19.07.2016 две незначительные ошибки синтаксиса фиксированной

+0

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

+6

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

+0

Это тоже работает для пользовательских элементов управления, спасибо! – Tyress

0

Более общий способ использования модели поведения предлагается в AttachedCommandBehavior V2 aka ACB и даже поддерживает несколько привязок событий в командовании,

Вот очень простой пример использования:

<Window x:Class="Example.YourWindow" 
     xmlns:local="clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior" 
     local:CommandBehavior.Event="Loaded" 
     local:CommandBehavior.Command="{Binding DoSomethingWhenWindowIsLoaded}" 
     local:CommandBehavior.CommandParameter="Some information" 
/> 
+0

Это работает в краткосрочной перспективе, но как насчет того, когда мы хотим подключить второе событие, например. команда 'Unloaded'? – ANeves

+0

@ANeves Тогда я думаю, что переход в пространство имен взаимодействия - это путь: и т. Д. Дополнительная информация: http://stackoverflow.com/questions/1048517/wpf-calling-commands-via-events – JoanComasFdz

+0

Да, thnak вам за помощь. То, что я хотел сделать, было то, что этот подход не очень полезен - я могу использовать 'local: MyAttachedBehaviors.LoadedCommand =" {Binding ShowLogInWindowCommand} "для простоты или сложность DLL взаимодействия. Это промежуточное решение интересно, но я не думаю, что это было бы очень полезно. – ANeves

-1

для VS 2013 Update 5 я не смог обойти «Невозможно привести объект типа„System.Reflection.RuntimeEventInfo“к типу«System.Reflection.MethodInfo». Вместо этого в директории «ядро» Я сделал простой интерфейс

interface ILoad 
    { 
     void load(); 
    } 

Моих ViewModel уже имели функцию нагрузки(), реализующую Iload. В моем .xaml.cs я вызываю LoadModel load() через ILoad.

private void ml_Loaded(object sender, RoutedEventArgs e) 
{ 
    (this.ml.DataContext as Core.ILoad).load(); 
} 

В xaml.cs ничего не знает о ViewModel, кроме POCO Iload, то ViewModel ничего не знает о xaml.cs. Событие ml_loaded сопоставляется с ViewModel load().

2

Update:

Я сделал сообщение о новой более гибкой версии методы связывания, который использует немного другой синтаксис здесь:

http://www.singulink.com/CodeIndex/post/updated-ultimate-wpf-event-method-binding

Полный код листинг доступен здесь :

https://gist.github.com/mikernet/7eb18408ffbcc149f1d9b89d9483fc19

Любые будущие обновления будут опубликованы в блоге, поэтому я предлагаю проверить их для последней версии.

Оригинал Ответ:

.NET 4.5+ теперь поддерживает расширения разметки на события. Я использовал это, чтобы создать привязки, которые могут быть использованы, как это метод:

<!-- 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); 
} 

Более подробную информацию можно найти здесь: http://www.singulink.com/CodeIndex/post/building-the-ultimate-wpf-event-method-binding-extension

Полный код класса можно получить здесь: https://gist.github.com/mikernet/4336eaa8ad71cb0f2e35d65ac8e8e161

+0

Этот фрагмент кода невероятно полезен, его следует поддерживать.У меня были некоторые проблемы с ним и изменил код, чтобы заставить его работать в моем решении. Https://gist.github.com/alexis-/1b1d8b9791cba7c6fae5905c81d22766 – Alexis

+0

В течение нескольких часов я опубликую обновление с помощью некоторого более нового кода, т успел. Это было быстрым доказательством концепции и еще не полностью протестировано. Используемая нами версия работает немного по-другому. Первый параметр - целевой объект (который может принимать полное связывание), второй параметр - это имя метода на целевом объекте, а остальные - параметры для передачи. Это дает вам большую гибкость при настройке различных привязок. –

+0

Не возражаете ли вы рассказать мне, какой у вас был вопрос, чтобы я мог убедиться, что у новой версии этого нет? –

Смежные вопросы