2012-11-26 25 views
14

Mam więc prostą konfigurację, autocompletebox z jej zdarzeniem Populacji, które chcę powiązać z poleceniem. UżywamJak przekazać argument zdarzenia do polecenia za pomocą wyzwalaczy?

clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity 

(jest tam lepszy nazw dla tej operacji?)

To nie jest wielka sprawa, aby ją związać, wielka sprawa jest przekazać tę PopulatingEventArgs argument polecenia związane.

Jak mogę to zrobić zgodnie z najlepszymi praktykami PRISM w szczególności i ogólnie MVVM?

+0

Nie umieszczaj tagów w tytule pytania. Zobacz [ten link] (http://meta.stackexchange.com/questions/10647/how-do-i-write-a-good-title) na pisanie dobrych tytułów;) –

Odpowiedz

24

Nie ma wbudowanego sposobu, więc oto jak to zrobić:

Klasyczny Interakcje wyzwalania służy tak:

<Button Content="I am a button"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="MouseEnter"> 
      <i:InvokeCommandAction Command="{Binding CommandWithNoArgs}" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</Button> 

Nie możemy uzyskać dostęp do EventArgs z MouseEnter wydarzenie przez wiązanie, więc będziemy musieli zmodyfikować fragment, który go wyrzuci.
Tak się składa, że ​​ten kawałek to InvokeCommandAction.

"Więc zamierzamy ją podklasować i zastąpić wygodną metodę, która czekała na nas cały czas" jest tym, co chciałbym napisać. Ale klasa jest zapieczętowana.

Więc będziemy mieć do podklasy jego rodzica (streszczenie) Klasa: TriggerAction<DependencyObject>

Najprostsza implementacja jest:

public class InteractiveCommand : TriggerAction<DependencyObject> 
{ 
    protected override void Invoke(object parameter) 
    { 
    } 
} 

I parameter to EventArgs!
Ale trzymaj się, to nie jest takie proste, musimy odtworzyć zachowanie zwykłego InvokeCommandAction.
Przez Reflector, ja ją dekompilowałem (ale mógłbyś spojrzeć na oficjalne źródło, jestem po prostu leniwy).

Nie będziemy się przejmować własnością zależną CommandParameter, zakładamy, że jeśli użyjesz tego zamiast InvokeCommandAction, za każdym razem będziesz potrzebować EventArgs.

Tu idzie pełną klasę (tylko WPF, zobacz EDIT dla Silverlight):

public class InteractiveCommand : TriggerAction<DependencyObject> 
{ 
    protected override void Invoke(object parameter) 
    { 
     if (base.AssociatedObject != null) 
     { 
      ICommand command = this.ResolveCommand(); 
      if ((command != null) && command.CanExecute(parameter)) 
      { 
       command.Execute(parameter); 
      } 
     } 
    } 

    private ICommand ResolveCommand() 
    { 
     ICommand command = null; 
     if (this.Command != null) 
     { 
      return this.Command; 
     } 
     if (base.AssociatedObject != null) 
     { 
      foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) 
      { 
       if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal)) 
       { 
        command = (ICommand)info.GetValue(base.AssociatedObject, null); 
       } 
      } 
     } 
     return command; 
    } 

    private string commandName; 
    public string CommandName 
    { 
     get 
     { 
      base.ReadPreamble(); 
      return this.commandName; 
     } 
     set 
     { 
      if (this.CommandName != value) 
      { 
       base.WritePreamble(); 
       this.commandName = value; 
       base.WritePostscript(); 
      } 
     } 
    } 

    #region Command 
    public ICommand Command 
    { 
     get { return (ICommand)GetValue(CommandProperty); } 
     set { SetValue(CommandProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty CommandProperty = 
     DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null)); 
    #endregion 
} 

Jak w przypadku każdego kodu pobieramy z internetu, Gorąco polecam przeczytanie całej klasy, i stara się zrozumieć co robi. Nie wrzucaj go do swojej aplikacji.

Teraz możemy zrobić:

<Button Content="I am a button"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="MouseEnter"> 
      <local:InteractiveCommand Command="{Binding CommandWithEventArgs}" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</Button> 

i kodeksem tyle:

#region CommandWithEventArgs 
DelegateCommand<MouseEventArgs> _CommandWithEventArgs; 
/// <summary> 
/// Exposes <see cref="CommandWithEventArgs(MouseEventArgs)"/>. 
/// </summary> 
public DelegateCommand<MouseEventArgs> CommandWithEventArgs 
{ 
    get { return _CommandWithEventArgs ?? (_CommandWithEventArgs = new DelegateCommand<MouseEventArgs>(CommandWithEventArgs)); } 
} 
#endregion 
public void CommandWithEventArgs(MouseEventArgs param) 
{ 
} 

a to wrap;)

EDIT: dla Silverlight, użyj tego kodu:

public class InteractiveCommand : TriggerAction<DependencyObject> 
    { 
     protected override void Invoke(object parameter) 
     { 
      if (base.AssociatedObject != null) 
      { 
       ICommand command = Command; 
       if ((command != null) && command.CanExecute(parameter)) 
       { 
        command.Execute(parameter); 
       } 
      } 
     } 

     #region Command 
     public ICommand Command 
     { 
      get { return (ICommand)GetValue(CommandProperty); } 
      set { SetValue(CommandProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty CommandProperty = 
      DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null)); 
     #endregion 
    } 

Należy jednak pamiętać, że jest mniej bezpieczny niż w przypadku pełnej wersji WPF (nie sprawdza typów, może ulec awarii przy zamrożonych elementach).

+0

Myślę, że jest po prostu bardzo elastyczny z pole, które prowadzi do pisania różnych rozszerzeń, aby wspierać rzeczy, które naszym zdaniem są podstawowe. –

+0

Po prostu wypróbowałem twój kod, nawet jeśli wpadłem na pomysł, że sam kod nie działa. (czy jest to kopiowanie/wklejanie z lepszego miejsca?) Zasadniczo CommandName nigdy nie jest przypisane, a zatem ResolveCommand zwraca wartość null, a całość nie działa z tego powodu. Istnieją również drobne problemy, takie jak base.WritePostscript(); nie są zdefiniowane w klasie bazowej, ale to nie jest ważne –

+0

OK, zmodyfikuj kod za pomocą kodu ułamkowego, który ma działać: http://pastie.org/5437478, http://pastie.org/5437483 Dziękujemy znowu i miłego dnia! –

35

Wypróbowałem InteractiveCommand i spowodowało to dla mnie problemy. Zamiast tego ustawiam odniesienie do Microsoft.Expression.Interactions i zawieram

xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="AppointmentEditing"> 
     <ei:CallMethodAction MethodName="AppointmentEditing" TargetObject="{Binding}" /> 
    </i:EventTrigger> 
    <i:EventTrigger EventName="ShowDialog"> 
     <ei:CallMethodAction MethodName="ShowDialog" TargetObject="{Binding}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 
... w moim UserControl.

następnie umieścić obsługi zdarzeń w moim ViewModel i ustawić zakres do publicznej wiadomości:

public void ShowDialog(object sender, ShowDialogEventArgs e) { 

} 

public void AppointmentEditing(object sender, AppointmentEditingEventArgs e) { 

} 

działa dobrze do tej pory.

+1

Jest to bardzo pomocne. – rajibdotnet

+5

Świetne !! Unikaj tego podklasowania i zezwól na używanie komend jako operatorów zdarzeń z kodu do tyłu. – isra60

+4

Dla mnie ten powinien być akceptowaną odpowiedzią. –