WPF:Blend 3 Interactions / Behaviours






4.94/5 (9投票s)
WPF 中的 Blend 3 Interactions / Behaviours
作为新 Blend3 版本的一部分,有一个名为 "Microsoft.Expression.Interactivity.dll" 的新 DLL。这个 DLL 非常棒,因为它形式化了许多 WPF 开发人员可能已经以自己的方式使用过的模式。它基本上形式化了 "附加行为" 模式,这个模式在提供此 DLL 之前,可以通过使用附加的 DP 来实现。
如果你想看一个只使用 DP 的附加行为的良好示例,可以看看 Josh Smith 撰写的优秀文章 www.codeproject.com 这里,因为它非常好。
正如我所说,"Microsoft.Expression.Interactivity.dll" 只是稍微标准化了这种模式。那么,它的一切是如何工作的呢?
行为
嗯,可以很容易地将行为添加到任何控件中。它只是一个继承自正确的 baseclass
并提供几个重写的问题
OnAttached
OnDetatched
然后,你只需要将行为附加到你想要使用这些行为的 UIElement
(s) 即可。在 XAML 中,附加行为看起来像这样
1: <Window x:Class="BlendBehaviors.Window1"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:interactivity="clr-namespace:Microsoft.Expression.Interactivity;
assembly=Microsoft.Expression.Interactivity"
5: xmlns:local="clr-namespace:BlendBehaviors;assembly=" >
6:
7: <Rectangle Width="50" Height="50" Canvas.Left="10" Canvas.Top="10"
8: Fill="Aqua">
9:
10: <interactivity:Interaction.Behaviors>
11: <local:DragBehavior/>
12: <local:ResizeBehavior/>
13: </interactivity:Interaction.Behaviors>
14: </Rectangle>
你能看到我们能够通过使用新的属性 "Behaviours
" 来添加行为吗?这很棒,那么这些行为实际上是什么样子的呢?嗯,在 Expression Blend 库 (http://gallery.expression.microsoft.com/site/items/behaviors) 中有几个,但现在,让我们看看我使用的一个。这是一个调整大小的行为,当附加到一个元素时,它将允许使用位于 AdornerLayer
中的 ResizeAdorner
来调整其大小。
ResizeBehavior
1: using System.Windows;
2: using System.Windows.Input;
3: using System.Windows.Media;
4: using Microsoft.Expression.Interactivity;
5: using System.Windows.Documents;
6: using System.Windows.Controls;
7:
8:
9: namespace BlendBehaviors
10: {
11:
12: /// <summary>
13: /// A simple Resizing Behavior that makes use
14: /// of a ResizingAdorner
15: /// </summary>
16: public class ResizeBehavior : Behavior<UIElement>
17: {
18: #region Data
19: private AdornerLayer adornerLayer;
20: private static Window parent;
21: private FrameworkElement fe;
22: private UIElement attachedElement;
23: #endregion
24:
25: #region Ctor
26: static ResizeBehavior()
27: {
28: parent = Application.Current.MainWindow;
29:
30: }
31: #endregion
32:
33: #region Behaviour Overrides
34:
35: protected override void OnAttached()
36: {
37: attachedElement = this.AssociatedObject;
38: fe = attachedElement as FrameworkElement;
39:
40: if (fe.Parent != null)
41: {
42: (fe.Parent as FrameworkElement).Loaded += ResizeBehaviorParent_Loaded;
43: }
44: }
45:
46: protected override void OnDetaching()
47: {
48: base.OnDetaching();
49: if (adornerLayer != null)
50: {
51: adornerLayer = null;
52: }
53: }
54: #endregion
55:
56: #region Private Methods
57: /// <summary>
58: /// Create the AdornerLayer when Parent for current Element loads
59: /// </summary>
60: private void ResizeBehaviorParent_Loaded(object sender, RoutedEventArgs e)
61: {
62: if (adornerLayer == null)
63: adornerLayer = AdornerLayer.GetAdornerLayer(sender as Visual);
64: attachedElement.MouseEnter += AttachedElement_MouseEnter;
65: }
66:
67: /// <summary>
68: /// When mouse enters, create a new Resizing Adorner
69: /// </summary>
70: private void AttachedElement_MouseEnter(object sender, MouseEventArgs e)
71: {
72: ResizingAdorner resizingAdorner = new ResizingAdorner(sender as UIElement);
73: resizingAdorner.MouseLeave += ResizingAdorner_MouseLeave;
74: adornerLayer.Add(resizingAdorner);
75: }
76:
77: /// <summary>
78: /// On mouse leave for the Resizing Adorner, remove the Resizing Adorner
79: /// from the AdornerLayer
80: /// </summary>
81: private void ResizingAdorner_MouseLeave(object sender, MouseEventArgs e)
82: {
83: if (sender != null)
84: {
85: adornerLayer.Remove(sender as ResizingAdorner);
86: }
87: }
88: #endregion
89:
90: }
91: }
而 ResizeAdorner
的代码是 Microsoft SDK 示例之一,如下所示
1: using System;
2: using System.Collections.Generic;
3: using System.Text;
4: using System.Windows;
5: using System.Windows.Controls;
6: using System.Windows.Controls.Primitives;
7: using System.Windows.Documents;
8: using System.Windows.Input;
9: using System.Windows.Media;
10:
11:
12: ///*********************************************
13: ///
14: /// This class was taken from the MSDN
15: /// Adorners Overview samples page
16: ///
17: ///*********************************************
18:
19:
20: namespace BlendBehaviors
21: {
22:
23: /// <summary>
24: /// A simple Resizing Adorner, that allows the user
25: /// to resize the Adorned element using 4 corner thumbs
26: /// </summary>
27: public class ResizingAdorner : Adorner
28: {
29: #region Data
30: // Resizing adorner uses Thumbs for visual elements.
31: // The Thumbs have built-in mouse input handling.
32: Thumb topLeft, topRight, bottomLeft, bottomRight;
33:
34: // To store and manage the adorner’s visual children.
35: VisualCollection visualChildren;
36: #endregion
37:
38: #region Ctor
39: // Initialize the ResizingAdorner.
40: public ResizingAdorner(UIElement adornedElement)
41: : base(adornedElement)
42: {
43: visualChildren = new VisualCollection(this);
44:
45: // Call a helper method to initialize the Thumbs
46: // with a customized cursors.
47: BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
48: BuildAdornerCorner(ref topRight, Cursors.SizeNESW);
49: BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW);
50: BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE);
51:
52: // Add handlers for resizing.
53: bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft);
54: bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight);
55: topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft);
56: topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight);
57: }
58: #endregion
59:
60: #region Private Methods
61: // Handler for resizing from the bottom-right.
62: private void HandleBottomRight(object sender, DragDeltaEventArgs args)
63: {
64: FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
65: Thumb hitThumb = sender as Thumb;
66:
67: if (adornedElement == null || hitThumb == null) return;
68: FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
69:
70: // Ensure that the Width and Height are properly initialized after the resize.
71: EnforceSize(adornedElement);
72:
73: // Change the size by the amount the user drags the mouse, as long as it’s larger
74: // than the width or height of an adorner, respectively.
75: adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange,
76: hitThumb.DesiredSize.Width);
77: adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height,
78: hitThumb.DesiredSize.Height);
79: }
80:
81: // Handler for resizing from the bottom-left.
82: private void HandleBottomLeft(object sender, DragDeltaEventArgs args)
83: {
84: FrameworkElement adornedElement = AdornedElement as FrameworkElement;
85: Thumb hitThumb = sender as Thumb;
86:
87: if (adornedElement == null || hitThumb == null) return;
88:
89: // Ensure that the Width and Height are properly initialized after the resize.
90: EnforceSize(adornedElement);
91:
92: // Change the size by the amount the user drags the mouse, as long as it’s larger
93: // than the width or height of an adorner, respectively.
94: adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange,
95: hitThumb.DesiredSize.Width);
96:
97: adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height,
98: hitThumb.DesiredSize.Height);
99: }
100:
101: // Handler for resizing from the top-right.
102: private void HandleTopRight(object sender, DragDeltaEventArgs args)
103: {
104: FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
105: Thumb hitThumb = sender as Thumb;
106:
107: if (adornedElement == null || hitThumb == null) return;
108: FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;
109:
110: // Ensure that the Width and Height are properly initialized after the resize.
111: EnforceSize(adornedElement);
112:
113: // Change the size by the amount the user drags the mouse, as long as it’s larger
114: // than the width or height of an adorner, respectively.
115: adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange,
116: hitThumb.DesiredSize.Width);
117:
118: adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange,
119: hitThumb.DesiredSize.Height);
120: }
121:
122: // Handler for resizing from the top-left.
123: private void HandleTopLeft(object sender, DragDeltaEventArgs args)
124: {
125: FrameworkElement adornedElement = AdornedElement as FrameworkElement;
126: Thumb hitThumb = sender as Thumb;
127:
128: if (adornedElement == null || hitThumb == null) return;
129:
130: // Ensure that the Width and Height are properly initialized after the resize.
131: EnforceSize(adornedElement);
132:
133: // Change the size by the amount the user drags the mouse, as long as it’s larger
134: // than the width or height of an adorner, respectively.
135: adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange,
136: hitThumb.DesiredSize.Width);
137:
138: adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange,
139: hitThumb.DesiredSize.Height);
140: }
141:
142: // Helper method to instantiate the corner Thumbs, set the Cursor property,
143: // set some appearance properties, and add the elements to the visual tree.
144: private void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
145: {
146: if (cornerThumb != null) return;
147:
148: cornerThumb = new Thumb();
149:
150: // Set some arbitrary visual characteristics.
151: cornerThumb.Cursor = customizedCursor;
152: cornerThumb.Height = cornerThumb.Width = 10;
153: cornerThumb.Opacity = 0.40;
154: cornerThumb.Background = new SolidColorBrush(Colors.MediumBlue);
155:
156: visualChildren.Add(cornerThumb);
157: }
158:
159: // This method ensures that the Widths and Heights are initialized.
160: // Sizing to content produces Width and Height values of Double.NaN.
161: // Because this Adorner explicitly resizes, the Width and Height
162: // need to be set first. It also sets the maximum size of the adorned element.
163: private void EnforceSize(FrameworkElement adornedElement)
164: {
165: if (adornedElement.Width.Equals(Double.NaN))
166: adornedElement.Width = adornedElement.DesiredSize.Width;
167: if (adornedElement.Height.Equals(Double.NaN))
168: adornedElement.Height = adornedElement.DesiredSize.Height;
169:
170: FrameworkElement parent = adornedElement.Parent as FrameworkElement;
171: if (parent != null)
172: {
173: adornedElement.MaxHeight = parent.ActualHeight;
174: adornedElement.MaxWidth = parent.ActualWidth;
175: }
176: }
177: #endregion
178:
179: #region Overrides
180: // Arrange the Adorners.
181: protected override Size ArrangeOverride(Size finalSize)
182: {
183: // desiredWidth and desiredHeight are the width and height of the element
184: //that’s being adorned.
185: // These will be used to place the ResizingAdorner at the corners of the
186: //adorned element.
187: double desiredWidth = AdornedElement.DesiredSize.Width;
188: double desiredHeight = AdornedElement.DesiredSize.Height;
189: // adornerWidth & adornerHeight are used for placement as well.
190: double adornerWidth = this.DesiredSize.Width;
191: double adornerHeight = this.DesiredSize.Height;
192:
193: topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2,
194: adornerWidth, adornerHeight));
195:
196: topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2,
197: -adornerHeight / 2, adornerWidth, adornerHeight));
198:
199: bottomLeft.Arrange(new Rect(-adornerWidth / 2,
200: desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
201:
202: bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2,
203: desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
204:
205: // Return the final size.
206: return finalSize;
207: }
208:
209: // Override the VisualChildrenCount and GetVisualChild properties to interface with
210: // the adorner’s visual collection.
211: protected override int VisualChildrenCount { get { return visualChildren.Count; } }
212: protected override Visual GetVisualChild(int index) { return visualChildren[index]; }
213: #endregion
214: }
215: }
因此,当我们运行附加的演示应用程序时,我们可以调整任何附加了这个行为的元素的大小(好的,我假设该元素在一个 Panel
等中,但你应该明白其中的含义)。
DragBehavior
这里是另一个行为(来自 Expression blend 团队),它允许拖动一个元素。
1: using System.Windows;
2: using System.Windows.Input;
3: using System.Windows.Media;
4: using Microsoft.Expression.Interactivity;
5:
6: ///*********************************************
7: ///
8: /// This class was originally taken from the
9: /// Expression Blend team blog
10: ///
11: ///*********************************************
12:
13:
14: namespace BlendBehaviors
15: {
16:
17: /// <summary>
18: /// A simple Resizing Behavior that makes use
19: /// of a ResizingAdorner
20: /// </summary>
21: public class DragBehavior : Behavior<UIElement>
22: {
23: #region Data
24: private bool isDragging = false;
25: private UIElement attachedElement;
26: private Window parent;
27: private Point lastPosition;
28: private TranslateTransform translatePosition;
29: #endregion
30:
31: #region Behaviour Overrides
32: protected override void OnAttached()
33: {
34: attachedElement = this.AssociatedObject;
35: parent = Application.Current.MainWindow;
36:
37: attachedElement.MouseLeftButtonDown += new MouseButtonEventHandler(MouseIsDown);
38: attachedElement.MouseLeftButtonUp += new MouseButtonEventHandler(MouseIsUp);
39: attachedElement.MouseMove += new MouseEventHandler(MouseIsMoving);
40: }
41: #endregion
42:
43: #region Private Methods
44: private void MouseIsMoving(object sender, MouseEventArgs e)
45: {
46: if (isDragging)
47: {
48: Point currentPosition = e.GetPosition(parent);
49:
50: double dX = currentPosition.X - lastPosition.X;
51: double dY = currentPosition.Y - lastPosition.Y;
52:
53: this.lastPosition = currentPosition;
54:
55: Transform oldTransform = attachedElement.RenderTransform;
56: TransformGroup rt = new TransformGroup();
57: TranslateTransform newPos = new TranslateTransform();
58: newPos.X = dX;
59: newPos.Y = dY;
60:
61: translatePosition = newPos;
62: if (oldTransform != null)
63: {
64: rt.Children.Add(oldTransform);
65: }
66: rt.Children.Add(newPos);
67:
68: MatrixTransform mt = new MatrixTransform();
69: mt.Matrix = rt.Value;
70:
71: if (currentPosition.X < 0 || currentPosition.Y < 0)
72: return;
73:
74: attachedElement.RenderTransform = mt;
75: }
76: }
77:
78: private void MouseIsUp(object sender, MouseButtonEventArgs e)
79: {
80: isDragging = false;
81:
82: attachedElement.ReleaseMouseCapture();
83: }
84:
85: private void MouseIsDown(object sender, MouseButtonEventArgs e)
86: {
87: isDragging = true;
88: lastPosition = e.GetPosition(parent);
89: attachedElement.CaptureMouse();
90: }
91: #endregion
92: }
93: }
TargetedTriggerAction(s)
在 "Microsoft.Expression.Interactivity.dll" 中,另一个不错的东西是 TargetedTriggerAction<T>
,这些非常酷,并且允许针对一个 Event
执行任意操作。例如,使用这些 TargetedTriggerAction<T>
,我们可以很容易地在发生 UIElement.MouseRightButtonUp
时运行一个 Command
。这在以前是一个相当大的任务,实际上几乎需要一些动态发出的程序集或 IL。
让我们接下来检查一下。首先在 XAML 中,我们可以这样做
1: <Border CornerRadius="10" Background="WhiteSmoke"
2: Grid.Row="0" BorderBrush="Black" BorderThickness="5">
3:
4: <!– Wire up a CommandAction that will fire an ICommand
5: when the event named by the EventTrigger EventName occurs–>
6: <interactivity:Interaction.Triggers>
7: <interactivity:EventTrigger EventName="MouseRightButtonUp">
8: <local:CommandAction Command="{Binding DemoCommand}"
9: SyncOwnerIsEnabled="True" />
10: </interactivity:EventTrigger>
11: </interactivity:Interaction.Triggers>
12:
13:
14: <TextBlock Text="Right-click to fire demo ViewModel bound command"
15: TextWrapping="Wrap" HorizontalAlignment="Center"
16: VerticalAlignment="Center"/>
17:
18:
19:
20: </Border>
正如你所看到的,当 MouseRightButtonUp RoutedEvent
发生在声明 EventTrigger
的 Border
上时,它将触发 CommandAction
。如果我们现在把注意力集中在 CommandAction
的实现上(同样,这来自 Expression Blend 库 http://gallery.expression.microsoft.com/site/items/behaviors)
1: using System;
2: using System.ComponentModel;
3: using System.Windows;
4: using System.Windows.Input;
5: using Microsoft.Expression.Interactivity;
6:
7:
8: ///*********************************************
9: ///
10: /// This class was originally taken from the
11: /// Expression Blend team blog
12: ///
13: ///*********************************************
14:
15: namespace BlendBehaviors
16: {
17:
18:
19: /// <summary>
20: /// The CommandAction allows the user to route a FrameworkElement’s
21: /// routed event to a Command.
22: /// For instance this makes it possible to specify–in Xaml–that
23: /// right-clicking on a Border element should execute the Application.Close
24: /// command (this example may not make much sense, but it does illustrate
25: /// what’s possible).
26: ///
27: /// CommandParameter and CommandTarget properties are provided for
28: /// consistency with the Wpf Command pattern.
29: ///
30: /// The action’s IsEnabled property will be updated according to the
31: /// Command’s CanExecute value.
32: ///
33: /// In addition a SyncOwnerIsEnabled property allows the user to specify
34: /// that the owner element should be enabled/disabled whenever the action
35: /// is enabled/disabled.
36: /// </summary>
37: public class CommandAction :
38: TargetedTriggerAction<FrameworkElement>,
39: ICommandSource
40: {
41: #region DPs
42:
43: #region Command DP
44: /// <summary>
45: /// The actual Command to fire when the
46: /// EventTrigger occurs, thus firing this
47: /// CommandAction
48: /// </summary>
49: [Category("Command Properties")]
50: public ICommand Command
51: {
52: get { return (ICommand)GetValue(CommandProperty); }
53: set { SetValue(CommandProperty, value); }
54: }
55:
56: public static readonly DependencyProperty CommandProperty =
57: DependencyProperty.Register(
58: "Command", typeof(ICommand), typeof(CommandAction),
59: new PropertyMetadata(
60: (ICommand)null, OnCommandChanged));
61:
62: private static void OnCommandChanged(DependencyObject d,
63: DependencyPropertyChangedEventArgs e)
64: {
65: var action = (CommandAction)d;
66: action.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
67: }
68:
69: #region Command implementation
70:
71: /// <summary>
72: /// This is a strong reference to the Command.CanExecuteChanged event handler.
73: /// The commanding system uses a weak reference and if we don’t enforce a
74: /// strong reference then the event handler will be gc’ed.
75: /// </summary>
76: private EventHandler CanExecuteChangedHandler;
77:
78:
79:
80: private void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
81: {
82: if (oldCommand != null)
83: UnhookCommand(oldCommand);
84: if (newCommand != null)
85: HookCommand(newCommand);
86: }
87:
88: private void UnhookCommand(ICommand command)
89: {
90: command.CanExecuteChanged -= CanExecuteChangedHandler;
91: UpdateCanExecute();
92: }
93:
94: private void HookCommand(ICommand command)
95: {
96: // Save a strong reference to the Command.CanExecuteChanged event handler.
97: // The commanding system uses a weak reference and if we don’t save a strong
98: // reference then the event handler will be gc’ed.
99: CanExecuteChangedHandler = new EventHandler(OnCanExecuteChanged);
100: command.CanExecuteChanged += CanExecuteChangedHandler;
101: UpdateCanExecute();
102: }
103:
104: private void OnCanExecuteChanged(object sender, EventArgs e)
105: {
106: UpdateCanExecute();
107: }
108:
109: private void UpdateCanExecute()
110: {
111: if (Command != null)
112: {
113: RoutedCommand command = Command as RoutedCommand;
114: if (command != null)
115: IsEnabled = command.CanExecute(CommandParameter, CommandTarget);
116: else
117: IsEnabled = Command.CanExecute(CommandParameter);
118: if (Target != null && SyncOwnerIsEnabled)
119: Target.IsEnabled = IsEnabled;
120: }
121: }
122:
123: #endregion
124:
125:
126: #endregion
127:
128: #region CommandParameter DP
129: /// <summary>
130: /// For consistency with the Wpf Command pattern
131: /// </summary>
132: [Category("Command Properties")]
133: public object CommandParameter
134: {
135: get { return (object)GetValue(CommandParameterProperty); }
136: set { SetValue(CommandParameterProperty, value); }
137: }
138:
139: public static readonly DependencyProperty CommandParameterProperty =
140: DependencyProperty.Register(
141: "CommandParameter", typeof(object), typeof(CommandAction),
142: new PropertyMetadata());
143: #endregion
144:
145: #region CommandTarget DP
146: /// <summary>
147: /// For consistency with the Wpf Command pattern
148: /// </summary>
149: [Category("Command Properties")]
150: public IInputElement CommandTarget
151: {
152: get { return (IInputElement)GetValue(CommandTargetProperty); }
153: set { SetValue(CommandTargetProperty, value); }
154: }
155:
156: public static readonly DependencyProperty CommandTargetProperty =
157: DependencyProperty.Register(
158: "CommandTarget", typeof(IInputElement), typeof(CommandAction),
159: new PropertyMetadata());
160: #endregion
161:
162: #region SyncOwnerIsEnabled DP
163: /// <summary>
164: /// Allows the user to specify that the owner element should be
165: /// enabled/disabled whenever the action is enabled/disabled.
166: /// </summary>
167: [Category("Command Properties")]
168: public bool SyncOwnerIsEnabled
169: {
170: get { return (bool)GetValue(SyncOwnerIsEnabledProperty); }
171: set { SetValue(SyncOwnerIsEnabledProperty, value); }
172: }
173:
174: /// <summary>
175: /// When SyncOwnerIsEnabled is true then changing CommandAction.IsEnabled
176: /// will automatically update the owner (Target) IsEnabled property.
177: /// </summary>
178: public static readonly DependencyProperty SyncOwnerIsEnabledProperty =
179: DependencyProperty.Register(
180: "SyncOwnerIsEnabled", typeof(bool), typeof(CommandAction),
181: new PropertyMetadata());
182: #endregion
183:
184: #endregion
185:
186: #region overrides
187: /// <summary>
188: /// Invoke is called when the EventTrigger associated with this
189: /// TargetedTriggerAction occurs. So we can obtain the associated
190: /// ICommand and simply execute it
191: /// </summary>
192: protected override void Invoke(object o)
193: {
194: if (Command != null)
195: {
196: var command = Command as RoutedCommand;
197: if (command != null)
198: command.Execute(CommandParameter, CommandTarget);
199: else
200: Command.Execute(CommandParameter);
201: }
202: }
203: #endregion
204: }
205: }
可以看到这段代码能够在 MouseRightButtonUp
RoutedEvent
发生在 Border 上时执行一个 ICommand
。很棒,对吧。
我已经把它连接到一个 demoViewModel
,它公开了一个单独的 ICommand
,当这个 EventTrigger
/ CommandAction
运行时,它会被执行。
1: using System;
2: using System.Collections.Generic;
3: using System.Collections.ObjectModel;
4: using System.IO;
5: using System.Linq;
6: using System.Text;
7: using System.Windows;
8: using System.Xml.Linq;
9: using System.Windows.Input;
10: using System.Linq.Expressions;
11: using System.Windows.Threading;
12: using System.Threading;
13: using System.Diagnostics;
14:
15: namespace BlendBehaviors
16: {
17:
18:
19:
20: /// <summary>
21: /// A small demo view model with a single
22: /// ICommand exposed, that will be executed
23: /// using the new Blend3 Interactivity
24: /// functionality, such as TargetedTriggerAction<T>
25: /// </summary>
26: public class DemoViewModel : ViewModelBase
27: {
28: #region Data
29: //Commands
30: private ICommand demoCommand = null;
31:
32: #endregion
33:
34: #region Ctor
35: public DemoViewModel()
36: {
37: //wire up command
38: demoCommand = new SimpleCommand
39: {
40: CanExecuteDelegate = x => true,
41: ExecuteDelegate = x =>
42: {
43: MessageBox.Show("In the ViewModel");
44: }
45: };
46: }
47: #endregion
48:
49: #region Public Properties
50:
51: public ICommand DemoCommand
52: {
53: get { return demoCommand; }
54: }
55: #endregion
56: }
57: }
这是一个小演示应用程序,其中包含了所有这些好东西。