【问题标题】:How to subscribe to event of Attached property inside custom control in Silverlight?如何在 Silverlight 的自定义控件中订阅 Attached 属性的事件?
【发布时间】:2011-12-27 08:46:00
【问题描述】:

我正在开发可用于在我的应用 UI 中进行交互的自定义​​控件。所以,我的想法是控件将绑定到IInteractionsProvider,它有它的事件。然后,我将调用此提供程序上的方法,该方法将向我的控件引发事件以执行它需要执行的操作。

问题是,我不知道如何在我的自定义控件中正确订阅事件InteractionRequired

基本上,我不知道如何正确地挂钩和取消挂钩事件以及在什么时间在控制范围内。

public interface IInteractionsProvider
    {
        event EventHandler InteractionRequested;

        void RequestInteraction(Action<object> callback);
    } 



public class MyInteractions : Control
    {
        public static readonly DependencyProperty ContainerProperty =
            DependencyProperty.Register("Container", typeof(Grid), typeof(IdattInteractions), new PropertyMetadata(null));

        public static readonly DependencyProperty InteractionsProviderProperty =
            DependencyProperty.Register("InteractionsProvider", typeof(IInteractionsProvider), typeof(IdattInteractions), new PropertyMetadata(null));

        public IdattInteractions()
        {
            DefaultStyleKey = typeof(MyInteractions);
        }

        public Grid Container
        {
            get { return GetValue(ContainerProperty) as Grid; }
            set { this.SetValue(ContainerProperty, value); }
        }

        public IInteractionsProvider InteractionsProvider
        {
            get { return (IInteractionsProvider)GetValue(InteractionsProviderProperty); }
            set { this.SetValue(InteractionsProviderProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (System.ComponentModel.DesignerProperties.IsInDesignTool) return;

            if (this.InteractionsProvider == null)
            {
                throw new NotSupportedException("InteractionsProvider wasn't specified. If you don't need interactions on this view - please remove MyInteractions from XAML");
            }

            if (this.Container != null)
            {
                if (this.Container.GetType() != typeof(Grid))
                {
                    throw new NotSupportedException("Specified container must be of Grid type");
                }
            }
            else
            {
                this.Container = TreeHelper.FindParentGridByName(this, "LayoutRoot") ?? TreeHelper.FindParent<Grid>(this);

                if (this.Container == null)
                {
                    throw new NotSupportedException("Container wasn't specified and parent Grid wasn't found");
                }
            }
        }
    }

【问题讨论】:

    标签: c# silverlight xaml mvvm


    【解决方案1】:

    这是你要找的吗?

    public IInteractionsProvider InteractionsProvider 
    { 
        get { return (IInteractionsProvider)GetValue(InteractionsProviderProperty); } 
        set {
            var oldValue = this.InteractionsProvider;
            if (oldValue != null)
                oldValue.InteractionRequested -= this.HandleInteractionRequested;
            if (value != null)
                value.InteractionRequested += this.HandleInteractionRequested;
            this.SetValue(InteractionsProviderProperty, value);
        } 
    } 
    
    private void HandleInteractionRequested(object sender, EventArgs e)
    {
        //...
    }
    

    【讨论】:

    • 使用依赖属性时,请始终使用属性更改回调。分配属性时并不总是调用标准的 .NET 属性设置器方法。例如,如果使用绑定为其分配 Silverlight 直接调用 SetValue,它不会调用您在答案中包含的设置器代码。顺便说一句,newValue 是从哪里来的?
    • ^^^ 他说的。 XAML 解析器完全绕过您的属性获取/设置定义。它是为了程序员的方便,仅此而已。除了调用 GetValue 或 SetValue 之外,您不应该在其中放置任何代码,因为绑定系统会绕过该代码。
    • @AnthonyWJones 感谢您的提示。 newValue 应该是 value;我更正了。
    【解决方案2】:

    要附加到依赖属性上的事件(或在分配后对依赖属性执行任何操作),您可以使用PropertyMetadata 上的回调委托。

        public static readonly DependencyProperty InteractionsProviderProperty = 
            DependencyProperty.Register("InteractionsProvider", typeof(IInteractionsProvider), typeof(IdattInteractions), new PropertyMetadata(null, OnInteractionsProviderPropertyChanged)); 
    
        private static void OnInteractionsProviderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
    
             var source = d As MyInteractions;
             if (source ! = null)
             {
                 var oldValue = (IInteractionsProvider)e.OldValue;
                 var newValue = (IInteractionsProvider)e.NewValue;
                 source.OnInteractionsProviderPropertyChanged(oldValue, newValue);
             }
        }
        private void OnInteractionsProviderPropertyChanged(IInteractionsProvider oldValue, IInteractionsProvider newValue)
        {
             if (oldValue != null)
                  oldValue -= InteractionsProvider_InteractionRequested;
    
             if (newValue != null)
                  newValue += InteractionsProvider_InteractionRequested;
        }
        private void InteractionsProvider_InteractionRequested(object sender, EventArgs e)
        {
            // Do Stuff
        }
    

    【讨论】:

    • phoog 建议的方式怎么样?我更喜欢这种方法,不确定是否有任何顾虑?
    • @katit:查看我对该答案的评论
    • 谢谢!我猜他的 newValue 应该是值。而且我猜在您的示例中的依赖属性声明中,它应该是 OnInteractionsProviderPropertyChanged 而不是 OnInteractionsProviderProperty,对吧?
    • @katit:不,在这种情况下 newValue 是 newValue。回调委托分配不正确,应该是OnInteractionsProviderPropertyChanged,我已更正。
    • @katit 在我的回答中,是的,newValue 应该是价值。我更正了。
    猜你喜欢
    • 1970-01-01
    • 2011-03-20
    • 2010-12-26
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多