Created
December 7, 2011 23:56
-
-
Save vbfox/1445370 to your computer and use it in GitHub Desktop.
CommandBindings from ICommands for WPF MVVM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace BlackFox | |
{ | |
using System; | |
using System.Windows; | |
static class Mvvm | |
{ | |
public static readonly DependencyProperty CommandBindingsProperty = DependencyProperty.RegisterAttached( | |
"CommandBindings", typeof(MvvmCommandBindingCollection), typeof(Mvvm), | |
new PropertyMetadata(null, OnCommandBindingsChanged)); | |
[AttachedPropertyBrowsableForType(typeof(UIElement))] | |
public static MvvmCommandBindingCollection GetCommandBindings(UIElement target) | |
{ | |
if (target == null) throw new ArgumentNullException("target"); | |
return (MvvmCommandBindingCollection)target.GetValue(CommandBindingsProperty); | |
} | |
public static void SetCommandBindings(UIElement target, MvvmCommandBindingCollection value) | |
{ | |
if (target == null) throw new ArgumentNullException("target"); | |
target.SetValue(CommandBindingsProperty, value); | |
} | |
private static void OnCommandBindingsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
var uiDependencyObject = d as UIElement; | |
if (uiDependencyObject == null) return; | |
var oldValue = e.OldValue as MvvmCommandBindingCollection; | |
if (oldValue != null) | |
{ | |
oldValue.DettachFrom(uiDependencyObject); | |
} | |
var newValue = e.NewValue as MvvmCommandBindingCollection; | |
if (newValue != null) | |
{ | |
newValue.AttachTo(uiDependencyObject); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace BlackFox | |
{ | |
using System; | |
using System.ComponentModel; | |
using System.Windows; | |
using System.Windows.Input; | |
class MvvmCommandBinding : Freezable | |
{ | |
UIElement uiElement; | |
readonly CommandBinding commandBinding; | |
public MvvmCommandBinding() | |
{ | |
commandBinding = new CommandBinding(); | |
commandBinding.CanExecute += OnCanExecute; | |
commandBinding.Executed += OnExecute; | |
} | |
#region Command | |
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( | |
"Command", typeof(ICommand), typeof(MvvmCommandBinding), | |
new PropertyMetadata(null, OnCommandChanged)); | |
static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
((MvvmCommandBinding)d).OnCommandChanged((ICommand)e.NewValue); | |
} | |
void OnCommandChanged(ICommand newValue) | |
{ | |
commandBinding.Command = newValue; | |
} | |
[Bindable(true)] | |
public ICommand Command | |
{ | |
get { return (ICommand) GetValue(CommandProperty); } | |
set { SetValue(CommandProperty, value); } | |
} | |
#endregion | |
#region Target | |
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register( | |
"Target", typeof(ICommand), typeof(MvvmCommandBinding), | |
new PropertyMetadata(null, OnTargetChanged)); | |
[Bindable(true)] | |
public ICommand Target | |
{ | |
get { return (ICommand)GetValue(TargetProperty); } | |
set { SetValue(TargetProperty, value); } | |
} | |
static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
((MvvmCommandBinding)d).OnTargetChanged((ICommand)e.OldValue, (ICommand)e.NewValue); | |
} | |
void OnTargetChanged(ICommand oldValue, ICommand newValue) | |
{ | |
if (oldValue != null) | |
{ | |
oldValue.CanExecuteChanged -= OnTargetCanExecuteChanged; | |
} | |
if (newValue != null) | |
{ | |
newValue.CanExecuteChanged += OnTargetCanExecuteChanged; | |
} | |
CommandManager.InvalidateRequerySuggested(); | |
} | |
#endregion | |
#region CanExecuteChangedSuggestRequery | |
public static readonly DependencyProperty CanExecuteChangedSuggestRequeryProperty | |
= DependencyProperty.Register( | |
"CanExecuteChangedSuggestRequery", typeof(bool), typeof(MvvmCommandBinding), | |
new PropertyMetadata(false, OnCanExecuteChangedSuggestRequeryChanged)); | |
[Bindable(true)] | |
public bool CanExecuteChangedSuggestRequery | |
{ | |
get { return (bool)GetValue(CanExecuteChangedSuggestRequeryProperty); } | |
set { SetValue(CanExecuteChangedSuggestRequeryProperty, value); } | |
} | |
static void OnCanExecuteChangedSuggestRequeryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
((MvvmCommandBinding)d).OnCanExecuteChangedSuggestRequeryChanged((bool)e.NewValue); | |
} | |
void OnCanExecuteChangedSuggestRequeryChanged(bool newValue) | |
{ | |
if (newValue) | |
{ | |
CommandManager.InvalidateRequerySuggested(); | |
} | |
} | |
#endregion | |
#region On event | |
void OnTargetCanExecuteChanged(object sender, EventArgs e) | |
{ | |
if (CanExecuteChangedSuggestRequery) | |
{ | |
CommandManager.InvalidateRequerySuggested(); | |
} | |
} | |
void OnExecute(object sender, ExecutedRoutedEventArgs e) | |
{ | |
if (Target == null) return; | |
e.Handled = true; | |
Target.Execute(e.Parameter); | |
} | |
void OnCanExecute(object sender, CanExecuteRoutedEventArgs e) | |
{ | |
if (Target == null) return; | |
e.Handled = true; | |
e.CanExecute = false; | |
e.CanExecute = Target.CanExecute(e.Parameter); | |
} | |
#endregion | |
#region Attach / Dettach | |
internal void DettachFrom(UIElement uiDependencyObject) | |
{ | |
if (uiDependencyObject == null) throw new ArgumentNullException("uiDependencyObject"); | |
WritePreamble(); | |
if (uiDependencyObject != uiElement) return; | |
Dettach(); | |
} | |
void Dettach() | |
{ | |
uiElement.CommandBindings.Remove(commandBinding); | |
uiElement = null; | |
} | |
internal void AttachTo(UIElement uiDependencyObject) | |
{ | |
if (uiDependencyObject == null) throw new ArgumentNullException("uiDependencyObject"); | |
WritePreamble(); | |
if (uiElement != null) | |
{ | |
Dettach(); | |
} | |
uiElement = uiDependencyObject; | |
uiDependencyObject.CommandBindings.Add(commandBinding); | |
} | |
#endregion | |
protected override Freezable CreateInstanceCore() | |
{ | |
return new MvvmCommandBinding(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace BlackFox | |
{ | |
using System; | |
using System.Collections.Specialized; | |
using System.Windows; | |
using System.Windows.Input; | |
using System.Windows.Markup; | |
/// <summary> | |
/// Set an element <see cref="UIElement.CommandBindings"/> with a syntax allowing to specify an | |
/// <see cref="ICommand"/> instance using bindings if required. | |
/// </summary> | |
/// <example> | |
/// <u:Mvvm.CommandBindings> | |
/// <u:MvvmCommandBindingCollection> | |
/// <u:MvvmCommandBinding Command="cmd:RoutedCommands.SomeCommand" | |
/// Target="{Binding CommandInViewModel}" /> | |
/// </u:MvvmCommandBindingCollection> | |
/// </u:Mvvm.CommandBindings> | |
/// </example> | |
[ContentProperty("Commands")] | |
class MvvmCommandBindingCollection : Freezable | |
{ | |
// Normally the inheritance context only goes to the logical and visual tree. But there are some additional | |
// "Pointers" that exists to simplify XAML programming. The one that we use there is that the context is | |
// propagated when a hierarchy of Freezable is inside a FrameworkElement. | |
// | |
// It is acheived by the facts that : | |
// * This class is Freezable | |
// * The collection property is a dependency property | |
// * The collection is Freezable (FreezableCollection<T> is an Animatable that is a Freezable) | |
// * The objects inside the collection are instances of Freezable | |
static readonly DependencyPropertyKey commandsPropertyReadWrite = | |
DependencyProperty.RegisterReadOnly("Commands", typeof(FreezableCollection<MvvmCommandBinding>), | |
typeof(MvvmCommandBindingCollection), null); | |
public static readonly DependencyProperty CommandsProperty = commandsPropertyReadWrite.DependencyProperty; | |
public FreezableCollection<MvvmCommandBinding> Commands | |
{ | |
get { return (FreezableCollection<MvvmCommandBinding>)GetValue(CommandsProperty);; } | |
private set { SetValue(commandsPropertyReadWrite, value); } | |
} | |
UIElement uiElement; | |
public MvvmCommandBindingCollection() | |
{ | |
Commands = new FreezableCollection<MvvmCommandBinding>(); | |
((INotifyCollectionChanged)Commands).CollectionChanged += CommandsChanged; | |
} | |
void CommandsChanged(object sender, NotifyCollectionChangedEventArgs e) | |
{ | |
if (uiElement == null) return; | |
if (e.Action == NotifyCollectionChangedAction.Add | |
|| e.Action == NotifyCollectionChangedAction.Replace) | |
{ | |
foreach (MvvmCommandBinding command in e.NewItems) | |
{ | |
command.AttachTo(uiElement); | |
} | |
} | |
else if (e.Action == NotifyCollectionChangedAction.Remove | |
|| e.Action == NotifyCollectionChangedAction.Replace) | |
{ | |
foreach (MvvmCommandBinding command in e.OldItems) | |
{ | |
command.DettachFrom(uiElement); | |
} | |
} | |
} | |
internal void DettachFrom(UIElement uiDependencyObject) | |
{ | |
if (uiDependencyObject == null) throw new ArgumentNullException("uiDependencyObject"); | |
WritePreamble(); | |
if (uiDependencyObject != uiElement) return; | |
Dettach(); | |
} | |
void Dettach() | |
{ | |
foreach (var command in Commands) | |
{ | |
command.DettachFrom(uiElement); | |
} | |
uiElement = null; | |
} | |
internal void AttachTo(UIElement uiDependencyObject) | |
{ | |
if (uiDependencyObject == null) throw new ArgumentNullException("uiDependencyObject"); | |
WritePreamble(); | |
if (uiElement != null) | |
{ | |
Dettach(); | |
} | |
uiElement = uiDependencyObject; | |
foreach (var command in Commands) | |
{ | |
command.AttachTo(uiElement); | |
} | |
} | |
protected override Freezable CreateInstanceCore() | |
{ | |
return new MvvmCommandBindingCollection(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Window x:Class="BlackFox.SampleWindow" | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:f="clr-namespace:BlackFox" | |
> | |
<f:Mvvm.CommandBindings> | |
<f:MvvmCommandBindingCollection> | |
<f:MvvmCommandBinding Command="f:MyRoutedCommands.SomeRoutedCommand" | |
Target="{Binding MyCommandInViewModel}" | |
CanExecuteChangedSuggestRequery="True" /> | |
</f:MvvmCommandBindingCollection> | |
</f:Mvvm.CommandBindings> | |
</Window> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment