어제 Prism 포럼에CommandParameterBehavior
게시 한 나의 것을 사용하실 수 있습니다 . 원인이 변경되면 누락 된 동작을 추가합니다 .CommandParameter
Command
다시 조회 할 수 있습니다.
PropertyDescriptor.AddValueChanged
나중에 호출하지 않고 호출 하면 발생하는 메모리 누수를 피하려는 시도로 인해 여기에 약간의 복잡성이 있습니다.PropertyDescriptor.RemoveValueChanged
. 나는 ekement가 언로드 될 때 핸들러를 등록 해제함으로써 그것을 고치려고한다.
IDelegateCommand
Prism을 사용하지 않는 한 (그리고 Prism 라이브러리에 저와 같은 변경을하고 싶지 않다면) 아마도 항목을 제거해야 할 것입니다 . 또한 우리는 일반적으로 RoutedCommand
여기에서 s를 사용하지 않습니다 (우리는 DelegateCommand<T>
거의 모든 것에 프리즘을 사용합니다 ). 그래서 CommandManager.InvalidateRequerySuggested
알려진 우주 나 그 어떤 것을 파괴하는 일종의 양자 파동 붕괴 캐스케이드를 시작하라는 내 전화에 책임을지지 마십시오 .
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
namespace Microsoft.Practices.Composite.Wpf.Commands
{
/// <summary>
/// This class provides an attached property that, when set to true, will cause changes to the element's CommandParameter to
/// trigger the CanExecute handler to be called on the Command.
/// </summary>
public static class CommandParameterBehavior
{
/// <summary>
/// Identifies the IsCommandRequeriedOnChange attached property
/// </summary>
/// <remarks>
/// When a control has the <see cref="IsCommandRequeriedOnChangeProperty" />
/// attached property set to true, then any change to it's
/// <see cref="System.Windows.Controls.Primitives.ButtonBase.CommandParameter" /> property will cause the state of
/// the command attached to it's <see cref="System.Windows.Controls.Primitives.ButtonBase.Command" /> property to
/// be reevaluated.
/// </remarks>
public static readonly DependencyProperty IsCommandRequeriedOnChangeProperty =
DependencyProperty.RegisterAttached("IsCommandRequeriedOnChange",
typeof(bool),
typeof(CommandParameterBehavior),
new UIPropertyMetadata(false, new PropertyChangedCallback(OnIsCommandRequeriedOnChangeChanged)));
/// <summary>
/// Gets the value for the <see cref="IsCommandRequeriedOnChangeProperty"/> attached property.
/// </summary>
/// <param name="target">The object to adapt.</param>
/// <returns>Whether the update on change behavior is enabled.</returns>
public static bool GetIsCommandRequeriedOnChange(DependencyObject target)
{
return (bool)target.GetValue(IsCommandRequeriedOnChangeProperty);
}
/// <summary>
/// Sets the <see cref="IsCommandRequeriedOnChangeProperty"/> attached property.
/// </summary>
/// <param name="target">The object to adapt. This is typically a <see cref="System.Windows.Controls.Primitives.ButtonBase" />,
/// <see cref="System.Windows.Controls.MenuItem" /> or <see cref="System.Windows.Documents.Hyperlink" /></param>
/// <param name="value">Whether the update behaviour should be enabled.</param>
public static void SetIsCommandRequeriedOnChange(DependencyObject target, bool value)
{
target.SetValue(IsCommandRequeriedOnChangeProperty, value);
}
private static void OnIsCommandRequeriedOnChangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is ICommandSource))
return;
if (!(d is FrameworkElement || d is FrameworkContentElement))
return;
if ((bool)e.NewValue)
{
HookCommandParameterChanged(d);
}
else
{
UnhookCommandParameterChanged(d);
}
UpdateCommandState(d);
}
private static PropertyDescriptor GetCommandParameterPropertyDescriptor(object source)
{
return TypeDescriptor.GetProperties(source.GetType())["CommandParameter"];
}
private static void HookCommandParameterChanged(object source)
{
var propertyDescriptor = GetCommandParameterPropertyDescriptor(source);
propertyDescriptor.AddValueChanged(source, OnCommandParameterChanged);
// N.B. Using PropertyDescriptor.AddValueChanged will cause "source" to never be garbage collected,
// so we need to hook the Unloaded event and call RemoveValueChanged there.
HookUnloaded(source);
}
private static void UnhookCommandParameterChanged(object source)
{
var propertyDescriptor = GetCommandParameterPropertyDescriptor(source);
propertyDescriptor.RemoveValueChanged(source, OnCommandParameterChanged);
UnhookUnloaded(source);
}
private static void HookUnloaded(object source)
{
var fe = source as FrameworkElement;
if (fe != null)
{
fe.Unloaded += OnUnloaded;
}
var fce = source as FrameworkContentElement;
if (fce != null)
{
fce.Unloaded += OnUnloaded;
}
}
private static void UnhookUnloaded(object source)
{
var fe = source as FrameworkElement;
if (fe != null)
{
fe.Unloaded -= OnUnloaded;
}
var fce = source as FrameworkContentElement;
if (fce != null)
{
fce.Unloaded -= OnUnloaded;
}
}
static void OnUnloaded(object sender, RoutedEventArgs e)
{
UnhookCommandParameterChanged(sender);
}
static void OnCommandParameterChanged(object sender, EventArgs ea)
{
UpdateCommandState(sender);
}
private static void UpdateCommandState(object target)
{
var commandSource = target as ICommandSource;
if (commandSource == null)
return;
var rc = commandSource.Command as RoutedCommand;
if (rc != null)
{
CommandManager.InvalidateRequerySuggested();
}
var dc = commandSource.Command as IDelegateCommand;
if (dc != null)
{
dc.RaiseCanExecuteChanged();
}
}
}
}