by Corrado Cavalli via Corrado's BLogs on 8/7/2009 3:10:33 PM
L’altro giorno stavo chattando con Larent Bugnion riguardo nuove features da aggiungere nel suo progetto M-V-VM light toolkit ed entrambi eravamo concordi nella necessità di aggiungere un behavior che mappasse un generico evento verso un comando esposto dal ViewModel. Questa necessità è ancor più sentita in Silverlight dove il meccanismo di commanding, ICommand a parte, non è presente.
Un esempio di possibile attached behavior è quello che segue:
1: public static class EventCommand
2: {
3: public static readonly DependencyProperty CommandProperty =
4: DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null));
5:
6: public static ICommand GetCommand(DependencyObject d)
7: {
8: return (ICommand)d.GetValue(CommandProperty);
9: }
10:
11: public static void SetCommand(DependencyObject d, ICommand value)
12: {
13: d.SetValue(CommandProperty, value);
14: }
15:
16: public static readonly DependencyProperty RoutedEventProperty =
17: DependencyProperty.RegisterAttached("RoutedEvent", typeof(String),
18: typeof(EventCommand), new PropertyMetadata((String)String.Empty, new PropertyChangedCallback(OnRoutedEventNameChanged)));
19:
20:
21: public static String GetRoutedEvent(DependencyObject d)
22: {
23: return (String)d.GetValue(RoutedEventProperty);
24: }
25:
26: public static void SetRoutedEvent(DependencyObject d, String value)
27: {
28: d.SetValue(RoutedEventProperty, value);
29: }
30:
31:
32: private static void OnRoutedEventNameChanged(DependencyObject d,
33: DependencyPropertyChangedEventArgs e)
34: {
35: String routedEvent = (String)e.NewValue;
36: if (d == null || String.IsNullOrEmpty(routedEvent)) return;
37:
38: EventHooker eventHooker = new EventHooker();
39: EventInfo eventInfo = d.GetType().GetEvent(routedEvent, BindingFlags.Public | BindingFlags.Instance);
40: if (eventInfo != null)
41: {
42: eventInfo.RemoveEventHandler(d,
43: eventHooker.GetNewEventHandlerToRunCommand(eventInfo));
44:
45: eventInfo.AddEventHandler(d,
46: eventHooker.GetNewEventHandlerToRunCommand(eventInfo));
47: }
48: }
49: }
50:
51: sealed class EventHooker
52: {
53: public Delegate GetNewEventHandlerToRunCommand(EventInfo eventInfo)
54: {
55: return Delegate.CreateDelegate(eventInfo.EventHandlerType, this,
56: GetType().GetMethod("OnEventRaised", BindingFlags.NonPublic | BindingFlags.Instance));
57: }
58:
59: private void OnEventRaised(object sender, EventArgs e)
60: {
61: ICommand command = (ICommand)(sender as DependencyObject). GetValue(EventCommand.CommandProperty);
62: if (command != null) command.Execute(null);
63: }
64: }
Il quale può essere usato in questo modo:
1: <ListBox Margin="10"
2: Grid.Row="1"
3: this:EventCommand.RoutedEvent="SelectionChanged"
4: this:EventCommand.Command="{Binding ButtonCommand}"
5: ItemsSource="{Binding Items}"
6: ItemTemplate="{StaticResource DataTemplate1}" />
7:
8: <Button Content="{Binding ButtonContent}"
9: this:EventCommand.RoutedEvent="Click"
10: this:EventCommand.Command="{Binding ButtonCommand}"
11: Grid.Row="2"
12: Margin="10" />
Rimane da risolvere un caso altrettanto frequente in architetture basate su M-V-VM ovvero mappare più eventi dello stesso elemento verso command diversi e questo, specialmente in Silverlight, non è proprio banale, per una serie di ‘mancanze’ fondamentali rispetto a WPF. Fortunatamente durnate la chiaccherata Laurent ipotizza che negli Expression Blend Samples ci sia già tutto quello che serve. Scaricati, installati e ora, anche in un progetto Silverlight per mappare un evento verso un Command non si deve far altro che selezionare un InvokeDataCommand e draggarlo sul controllo, selezionare l’evento, Command di destinazione ed eventuale parametro.
Ciò che rende questi behaviors ancora più interessanti è il fatto di poter associare più InvokeDataCommand allo stesso controllo risolvendo egregiamente la necessità iniziale
1: <Button Content="{Binding ButtonContent}"
2: Grid.Row="2"
3: Margin="10" >
4: <i:Interaction.Triggers>
5: <i:EventTrigger EventName="Click">
6: <si:InvokeDataCommand Command="{Binding ButtonCommand, Mode=OneWay}"/>
7: </i:EventTrigger>
8: <i:EventTrigger EventName="MouseLeave">
9: <si:InvokeDataCommand Command="{Binding ButtonCommand, Mode=OneWay}"/>
10: </i:EventTrigger>
11: </i:Interaction.Triggers>
12: </Button>
Original Post: Expression Blend Samples = M-V-VM PowerTools
The content of the postings is owned by the respective author. Silverlight Feeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on Silverlight Feeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.