WPF Custom Command And Binding
using System;
using System.Collections.Generic;
using System.Windows.Input; namespace WPF.Commands
{
/// <summary>
/// This class allows delegating the commanding logic to methods passed as parameters,
/// and enables a View to bind commands to objects that are not part of the element tree.
/// </summary>
public class DelegateCommand : ICommand
{
#region Constructors /// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action executeMethod)
: this(executeMethod, null, false)
{
} /// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
} /// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
} _executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
} #endregion #region Public Methods /// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute()
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod();
}
return true;
} /// <summary>
/// Execution of the command
/// </summary>
public void Execute()
{
if (_executeMethod != null)
{
_executeMethod();
}
} /// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
} /// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
} /// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
} #endregion #region ICommand Members /// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, );
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
} /// <summary>
///
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
bool ICommand.CanExecute(object parameter)
{
return CanExecute();
} /// <summary>
///
/// </summary>
/// <param name="parameter"></param>
void ICommand.Execute(object parameter)
{
Execute();
} #endregion #region Data
/// <summary>
///
/// </summary>
private readonly Action _executeMethod = null;
/// <summary>
///
/// </summary>
private readonly Func<bool> _canExecuteMethod = null;
/// <summary>
///
/// </summary>
private bool _isAutomaticRequeryDisabled = false;
/// <summary>
///
/// </summary>
private List<WeakReference> _canExecuteChangedHandlers; #endregion
} /// <summary>
/// This class allows delegating the commanding logic to methods passed as parameters,
/// and enables a View to bind commands to objects that are not part of the element tree.
/// </summary>
/// <typeparam name="TExecuteParameter">Type of the parameter passed to the delegates</typeparam>
public class DelegateCommand<TExecuteParameter> : ICommand
{
#region Constructors /// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<TExecuteParameter> onExecute)
: this(onExecute, null, false)
{
} /// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<TExecuteParameter> onExecute, Func<TExecuteParameter, bool> canExecute)
: this(onExecute, canExecute, false)
{
} /// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<TExecuteParameter> onExecute, Func<TExecuteParameter, bool> canExecute, bool isAutomaticRequeryDisabled)
{
if (onExecute == null)
{
throw new ArgumentNullException("executeMethod");
}
_onExecute = onExecute;
_canExecute = canExecute;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
} #endregion #region Public Methods /// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(TExecuteParameter parameter)
{
if (_canExecute != null)
{
return _canExecute(parameter);
}
return true;
} /// <summary>
/// Execution of the command
/// </summary>
public void Execute(TExecuteParameter parameter)
{
if (_onExecute != null)
{
_onExecute(parameter);
}
} /// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
} /// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
} /// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
} #endregion #region ICommand Members /// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, );
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
} /// <summary>
///
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
bool ICommand.CanExecute(object parameter)
{
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
var type = typeof(TExecuteParameter);
if (type.IsValueType && type.IsPrimitive)
{
if (int.TryParse(parameter.ToString(), out int intResult))
{
return CanExecute((TExecuteParameter)(object)intResult);
}
} if (parameter == null && type.IsValueType)
{
return (_canExecute == null);
}
return CanExecute((TExecuteParameter)parameter);
} /// <summary>
///
/// </summary>
/// <param name="parameter"></param>
void ICommand.Execute(object parameter)
{
Execute((TExecuteParameter)parameter);
} #endregion #region Data
/// <summary>
///
/// </summary>
private readonly Action<TExecuteParameter> _onExecute = null;
/// <summary>
///
/// </summary>
private readonly Func<TExecuteParameter, bool> _canExecute = null;
/// <summary>
///
/// </summary>
private bool _isAutomaticRequeryDisabled = false;
/// <summary>
///
/// </summary>
private List<WeakReference> _canExecuteChangedHandlers; #endregion
} /// <summary>
/// This class contains methods for the CommandManager that help avoid memory leaks by
/// using weak references.
/// </summary>
internal class CommandManagerHelper
{
internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
{
if (handlers != null)
{
// Take a snapshot of the handlers before we call out to them since the handlers
// could cause the array to me modified while we are reading it. EventHandler[] callees = new EventHandler[handlers.Count];
int count = ; for (int i = handlers.Count - ; i >= ; i--)
{
WeakReference reference = handlers[i];
EventHandler handler = reference.Target as EventHandler;
if (handler == null)
{
// Clean up old handlers that have been collected
handlers.RemoveAt(i);
}
else
{
callees[count] = handler;
count++;
}
} // Call the handlers that we snapshotted
for (int i = ; i < count; i++)
{
EventHandler handler = callees[i];
handler(null, EventArgs.Empty);
}
}
} /// <summary>
///
/// </summary>
/// <param name="handlers"></param>
internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested += handler;
}
}
}
} /// <summary>
///
/// </summary>
/// <param name="handlers"></param>
internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested -= handler;
}
}
}
} /// <summary>
///
/// </summary>
/// <param name="handlers"></param>
/// <param name="handler"></param>
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler)
{
AddWeakReferenceHandler(ref handlers, handler, -);
} /// <summary>
///
/// </summary>
/// <param name="handlers"></param>
/// <param name="handler"></param>
/// <param name="defaultListSize"></param>
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize)
{
if (handlers == null)
{
handlers = (defaultListSize > ? new List<WeakReference>(defaultListSize) : new List<WeakReference>());
} handlers.Add(new WeakReference(handler));
} /// <summary>
///
/// </summary>
/// <param name="handlers"></param>
/// <param name="handler"></param>
internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler)
{
if (handlers != null)
{
for (int i = handlers.Count - ; i >= ; i--)
{
WeakReference reference = handlers[i];
EventHandler existingHandler = reference.Target as EventHandler;
if ((existingHandler == null) || (existingHandler == handler))
{
// Clean up old handlers that have been collected
// in addition to the handler that is to be removed.
handlers.RemoveAt(i);
}
}
}
}
}
}
<Button Width="60"
Height="30"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Command="{Binding TestCommand}"
CommandParameter="123">Test</Button>
WPF Custom Command And Binding的更多相关文章
- [WPF]如何调试Data Binding
前言 在WPF开发中,将ViewModel中对象绑定到UI上时,会出现明明已经将数据对象Binding到UI,但是UI上就是不显示等等的问题.这篇博客将介绍WPF Data Binding相关的内容, ...
- ClassLibary和WPF User Control LIbary和WPF Custom Control Libary的异同
说来惭愧,接触WPF这么长时间了,今天在写自定义控件时遇到一个问题:运行界面中并没有显示自定义控件,经调试发现原来没有加载Themes中的Generic.xaml. 可是为什么在其他solution中 ...
- Typora + PicGo-Core + Custom Command 实现上传图片到图床
教程参考 Typora+PicGo-Core(command line)+Gitee实现图片上传到图床 主要借鉴 picgo 操作命令 Typora + PicGo + Gitee 实现图片自动上传到 ...
- silverlight wpf DataTemplate Command binding
<Grid x:Name="LayoutRoot" Background="White"> <CommonControl:NoapDataGr ...
- wpf custom control
最近在做WPF,记录一下自定义控件的制作过程,源码请点击:源码. 1.目标 实现一个如图所示的可增减的数字框: 2.先画Template 可以在Generic.xaml中画,也可以用MergedDic ...
- WPF 定义Command
直接上代码: public class LoginDelegateCommand : ICommand { private Action _execute; private Predicate< ...
- Zara带你快速入门WPF(4)---Command与功能区控件
前言:许多数据驱动的应用程序都包含菜单和工具栏或功能区控件,允许用户控制操作,在WPF中,也可以使用功能区控件,所以这里介绍菜单和功能区控件. 一.菜单控件 在WPF中,菜单很容易使用Menu和Men ...
- WPF 自定义Command
无参Command: internal class DelegateCommand : ICommand { private readonly Action _execute; private rea ...
- Recommended Practices for WPF Custom Control Developers
I have always found that there isn’t enough documentation about Custom Control development in WPF. M ...
随机推荐
- 总结SQL Server窗口函数的简单使用
总结SQL Server窗口函数的简单使用 前言:我一直十分喜欢使用SQL Server2005/2008的窗口函数,排名函数ROW_NUMBER()尤甚.今天晚上我在查看SQL Server开发的相 ...
- spring 上传附件
jsp: <form class='uk-form' action="savelead" method="post" enctype="mult ...
- Slacklining 2017/2/7
原文 Proline Slacklining's expansion is still in process,but it already has a professional scene.Some ...
- 洛谷 P2922 [USACO08DEC]秘密消息Secret Message
题目描述 Bessie is leading the cows in an attempt to escape! To do this, the cows are sending secret bin ...
- The Singapore NRIC Check Digit
The Singapore NRIC number is made up of 7 digits and a letter behind. This letter is calculated from ...
- Linux OpenGL 实践篇-14-多实例渲染
多实例渲染 OpenGL的多实例渲染是一种连续执行多条相同的渲染命令的方法,并且每条命令产生的结果都有轻微的差异,通常用于渲染大量的几何物体. 设想一个场景,比如太空,我们需要渲染数以万记的星球,如果 ...
- Vue 打印预览功能
需求有几种情况: 1.直接在HTML写页面,将页面上的东西用A4纸打印出来: 2.后台传回PDF文件,前台浏览器预览并打印: 3.后台做好要打印的,传回图片,如base64编码,前台浏览器 预览并打印 ...
- The - Modcrab——使用贪心策略
一.题目信息 The - Modcrab 简单翻译一下:Vova有生命值h1,每次攻击值为a1,每瓶药水恢复生命值c1;Modcrab有生命值h2,每次攻击值为a2.在每个关卡开始,Vova有两种选择 ...
- Java加腾讯云实现短信验证码功能
一.概要 现如今在日常工作和生活中短信验证码对于我们来说是非常熟悉的,比较常见的注册账号或者交易支付时候,手机会收到一个短信验证码,我们可以通过验证码来有效验证身份,避免一些信息被盗. 验证身份 目前 ...
- WPF知识点全攻略06- WPF逻辑树(Logical Tree)和可视树(Visual Tree)
介绍概念之前,先来分析一段代码: xaml代码如下: <Window x:Class="WpfApp1.MainWindow" xmlns="http://sche ...