!!!更新!!!
好的,我更进一步。我扩展了扩展以执行所有工作,包括设置触发器集合。
TriggerCollectionExtension
完成所有繁重工作的扩展。注意:第一次调用 ProvideValue 时会加载样式,因此 TargetValue 是一个 Setter。
[ContentProperty("Triggers")]
public class TriggerCollectionExtension : MarkupExtension
{
public string EventName { get; set; }
public string CommandName { get; set; }
public object CommandParameter { get; set; }
public System.Windows.Interactivity.TriggerCollection Triggers { get; private set;}
public TriggerCollectionExtension()
{
var trigCollectionType =
typeof(System.Windows.Interactivity.TriggerCollection);
var triggers = (System.Windows.Interactivity.TriggerCollection)
trigCollectionType.GetConstructor(
BindingFlags. NonPublic | BindingFlags. Instance,
null, Type.EmptyTypes, null).Invoke (null);
// Cheat to get around this problem.
// must have IsFrozen set to false to modify
var methCreateCore = trigCollectionType.GetMethod("CreateInstanceCore",
BindingFlags.NonPublic | BindingFlags.Instance);
var cloneTriggers =
(System.Windows.Interactivity.TriggerCollection)
methCreateCore.Invoke(triggers, null);
this.Triggers = cloneTriggers;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var target = serviceProvider.GetService(typeof(IProvideValueTarget)) as
IProvideValueTarget;
// The first time this is called is when loading the style.
// At that point the TargetObject is of type Setter.
// Return this (The MarkupExtension) and it will be reevaluated when the style
// is applied.
var hostcontrol = target.TargetObject as Control;
if (hostcontrol != null)
{
var cloneTriggers = this.Triggers;
var eventTrigger = new EventTrigger(this.EventName);
var trigbase = eventTrigger as TriggerBase;
trigbase.Attach(hostcontrol);
var commandAction = new CommandAction(hostcontrol, this.CommandName,
this.CommandParameter);
eventTrigger.Actions.Add(commandAction);
cloneTriggers.Add(eventTrigger);
Interaction.SetShadowTriggers(hostcontrol, this.Triggers);
return null;
}
else
{
return this;
}
return null;
}
}
交互
TriggersCollection 的重新拥有/曝光。
<!-- language: c# -->
/// <summary>
/// Helps workaround the bug in the deployed interaction DLL.
/// The DependencyProperty is registered as ShadowTriggers and the Setter Getter is
/// SetTriggers() GetTriggers().
/// The result is compile error for XAML if anything but Shadowtriggers is used and
/// runtime error.
/// </summary>
public static class Interaction
{
static Interaction()
{
var interActionType = typeof(System.Windows.Interactivity.Interaction);
var triggersProperty = (DependencyProperty)interActionType.InvokeMember(
"TriggersProperty",
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetField,
null, null, null);
ShadowTriggersProperty = triggersProperty.AddOwner(typeof(Interaction));
}
public static readonly DependencyProperty ShadowTriggersProperty;
public static System.Windows.Interactivity.TriggerCollection
GetShadowTriggers(DependencyObject d)
{
return
(System.Windows.Interactivity.TriggerCollection)
d.GetValue(ShadowTriggersProperty);
}
public static void
SetShadowTriggers(
DependencyObject d,
System.Windows.Interactivity.TriggerCollection value)
{
d.SetValue(ShadowTriggersProperty, value);
}
}
CommandAction
在 DataContext 上查找 Command 的自定义 TriggerAction。
<!-- language: c# -->
public class CommandAction : TriggerAction<FrameworkElement>
{
FrameworkElement control;
private string commandName;
object commandParameter;
private ICommand actualCommand;
public CommandAction(FrameworkElement control, string commandName,
object commandParameter)
{
this.control = control;
this.commandName = commandName;
this.commandParameter = commandParameter;
object datacontext;
if (this.FindDataContext(this.control, out datacontext))
{
var datacontextType = datacontext.GetType();
var propCommand = datacontextType.GetProperty(this.commandName);
this.actualCommand = propCommand.GetValue(datacontext, null) as ICommand;
}
}
private bool FindDataContext(FrameworkElement control, out object datacontext)
{
datacontext = default(object);
var parent = VisualTreeHelper.GetParent(control);
while (parent != null)
{
var parentFrame = parent as FrameworkElement;
if (parentFrame != null)
{
datacontext = parentFrame.DataContext;
if (datacontext != null)
{
return true;
}
}
var parentFrameContent = parent as FrameworkContentElement;
if (parentFrameContent != null)
{
datacontext = parentFrameContent.DataContext;
if (datacontext != null)
{
return true;
}
}
parent = VisualTreeHelper.GetParent(parent);
}
return false;
}
protected override void Invoke(object parameter)
{
if (this.actualCommand != null)
{
if (this.actualCommand.CanExecute(parameter))
{
this.actualCommand.Execute(parameter);
}
}
}
}
哇长时间阅读器第一次发布代码。我终于明白了为什么代码并不总是那么好剪切和粘贴。提交此更新尝试了很多次。
我确信有诸如磁盘空间、解析或渲染速度之类的原因,并且编辑器会在提交失败时保持状态。