首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过样式设置隐藏的AttachedProperty

通过样式设置隐藏的AttachedProperty
EN

Stack Overflow用户
提问于 2010-11-01 09:50:55
回答 2查看 1.2K关注 0票数 0

我在使用System.Windows.Interactivity.Interaction附加行为类(来自Expression 4)时遇到了问题。我想在XAML样式元素中为System.Windows.Window类定义一对触发器。但是,由于TriggersProperty类的System.Windows.Interactivity.Interaction字段是私有的,而且这个类中没有SetTriggers方法,所以在运行以下代码时,出现了一个错误:Set属性System.Windows.Setter.Property抛出了一个异常。->值不能为null。

我非常想在样式中使用触发器和操作,因为我希望将它们用于我的window后代控件。当然,我可以使用我的自定义行为或者使用触发器模拟逻辑直接编码我的窗口后代类,但是我想使用已经存在的触发器和表达式库以及我自己的操作,而不是拒绝它们,仅仅因为交互类的TriggersProperty是隐藏的,而且我不能通过样式设置它。

这个问题有什么解决办法吗?用反射还是其他方式?

PS。我已经尝试声明带有TriggersProperty附加依赖项属性的自定义静态类,该属性是在AddOwner方法的帮助下注册的,但是没有帮助--最后,它仍然试图在同一个System.Windows.Interactivity.Interaction类中访问相同的TriggersProperty。

代码语言:javascript
运行
复制
<Window
    x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:windowsInteractivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
    <Window.Style>
        <Style TargetType="Window">
            <Setter Property="Title" Value="WindowStyleTest"/>
            <Setter Property="windowsInteractivity:Interaction.Triggers">
                <Setter.Value>
                    <windowsInteractivity:EventTrigger EventName="MouseDown"/>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Style>
</Window>
EN

回答 2

Stack Overflow用户

发布于 2012-12-05 15:48:40

更新更新

好的,我走得更远了一点。我扩展了扩展以执行所有工作,包括设置触发器集合。

TriggerCollectionExtension --完成所有繁重工作的扩展。注意:第一次调用ProvideValue时,它将来自加载样式,因此TargetValue是一个设置器。

代码语言:javascript
运行
复制
[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;
    }
}

Interaction:TriggersCollection的重新拥有/暴露。

代码语言:javascript
运行
复制
<!-- 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上查找命令的自定义TriggerAction。

代码语言:javascript
运行
复制
<!-- 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);
            }
        }
    }
}

哇长时间的读者第一次发布代码。我终于明白了为什么代码并不总是那么好地剪切和粘贴。花了这么多努力才提交了这一更新。

我确信有一些原因,如磁盘空间、解析或呈现速度,并且编辑器在提交失败时保持状态。

票数 3
EN

Stack Overflow用户

发布于 2010-11-01 12:18:15

我明白了,为什么会出现错误。这是因为在运行时,它通过字符串名称搜索附加的依赖项属性,即"ShadowTriggers“(正如它在System.Windows.Interactivity程序集、交互静态构造函数中指定的那样)。因此,我创建了自己的自定义静态类,并从System.Windows.Interaction继承触发器依赖项属性(通过反射和AddOwner,将属性公开为ShadowTriggersProperty)。啊,真灵!但是..。现在,我必须向样式的属性值设置器提供一个TriggerCollection实例,类的构造函数是内部的。假设这是一条不可能的路。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4067876

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档