Как подписаться на событие прикрепленного свойства внутри пользовательского элемента управления в Silverlight?

#c# #silverlight #xaml #mvvm

#c# #silverlight #xaml #mvvm

Вопрос:

Я работаю над пользовательским элементом управления, который я могу использовать для взаимодействия в пользовательском интерфейсе моего приложения. Итак, моя идея заключается в том, что элемент управления будет привязываться к 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");
                }
            }
        }
    }
  

Ответ №1:

Чтобы присоединяться к событиям в свойстве зависимости (или делать что-либо со свойством зависимости, когда оно назначено), вы можете использовать делегат обратного вызова в 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
    }
  

Комментарии:

1. Что насчет способа, предложенного phoog? Мне больше нравится этот подход, не уверен, есть ли какие-либо опасения по этому поводу?

2. @katit: Смотрите мой комментарий к этому ответу

3. Спасибо! Я думаю, его новым значением должно быть value. И я предполагаю, что в объявлении свойства зависимости в вашем примере это должно быть OnInteractionsProviderPropertyChanged, а не OnInteractionsProviderProperty, верно?

4. @katit: нет, в этом случае newValue — это newValue . Назначение делегата обратного вызова было неправильным, так и должно быть OnInteractionsProviderPropertyChanged , я исправил.

5. @katit в моем ответе, да, newValue должно быть значением. Я это исправил.

Ответ №2:

Это то, что вы ищете?

 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)
{
    //...
}
  

Комментарии:

1. При работе со свойствами зависимостей всегда используйте обратный вызов с измененным свойством. Стандартный метод установки свойств .NET не всегда вызывается при назначении свойства. Например, если привязка используется для назначения ему вызовов Silverlight SetValue напрямую, он не будет вызывать код настройки, который вы включили в свой ответ. Кстати, откуда берется newValue?

2. ^^^ Что он сказал. Анализатор XAML полностью обходит определение получения / установки вашего свойства. Это сделано для удобства программиста, не более. Вы никогда не должны помещать туда какой-либо код, кроме вызова GetValue или setValue, потому что система привязки обходит этот код.

3. @AnthonyWJones спасибо за совет. newValue должно было быть value ; Я исправил это.