Search code examples
c#wpf.net-8.0attached-properties

Access self in attached property changed event


Let's say I have control A that has attached property AP. And a control B uses it as A.AP="value".

The attached property changed event signature is the same as dependency property, only d is now the element that is attaching i.e. B. How do I access A inside the changed event?

I want to hide A if AP == null and more

private static void OnApChanged
    (DependencyObject d, DependencyPropertyChangedEventArgs e)

Please note that I am aware that "usually" an attached property use is to set something on the attaching control i.e. A would normally manipulate B properties in order to achieve something. But it is just one scenario. I am working on different scenario when B doesn't know about A existence - A is buried somewhere in the visual tree (or might even not be there at all) and what I need is for B actually set AP to a string and A should be able to react on changes and work with the value. It does sound a lot like dependency property (which attached properties are very much alike) but only without B awareness of A.

At this moment what I am trying to do is this - I want a user control HelpButton (HB) which has a button and TopicName property on it. I want to have it in any arbitrary FrameworkElement children. Parent is not aware of it and HB is not aware of the parent. When there is TopicName set the HB is visible. If you click on it it opens help window using only TopicName, no other information required.


Solution

  • Let me summarize my understanding of the problem first. You have a HelpButton control named HB and it has a TopicName property. When TopicName is empty HB should be hidden, otherwise it should, when clicked, open a window based on TopicName (I'm assuming HelpButton is handling all this logic internally). However you want any other element to be able to set HB's TopicName without actually needing a reference to an instacne of HB itself.

    It appears what you're looking for isn't well suited to attached properties because attached properties still require an instance for the target object, while there is no instance of the owning type involved. If we make HelpButton the owning type, this doesn't work because HelpButton is the one whose property we need to change. If we make something else the owning type, this also doesn't work because no one else has access to an instance of HelpButton per your problem. So attached properties I think are the wrong track here.

    I would keep HelpButton.TopicName a standard DependencyProperty owned by HelpButton (i.e. not an attached property). Then I think a singleton view model that all UI elements can access/bind to serves the function you were trying to implement through an attached property. Here's a rough example:

    View Model

    public static class ViewModels
    {
        public static HelpViewModel HelpViewModel
        {
            get;
        } = new HelpViewModel();
    }
    
    public class HelpViewModel : ViewModel
    {
        #region string HelpTopic property
        private string _HelpTopic;
        public string HelpTopic
        {
            get
            {
                return _HelpTopic;
            }
            set
            {
                if (_HelpTopic == value)
                    return;
                _HelpTopic = value;
                OnPropertyChanged();
            }
        }
        #endregion
    }
    

    XAML:

    <HelpButton x:Name="HB" TopicName="{Binding 
            Source={x:Static local:ViewModels.HelpViewModel}, 
            Path=HelpTopic}" />
    

    This way anyone can change ViewModels.HelpViewModel.HelpTopic, from anywhere, without needing access to the HelpButton instance.

    Just note even if you're not following a strict MVVM pattern (you may or may not be), binding to a backing view model here to serve as the common state is gonna be much easier than trying to have controls directly manipulate each others' properties.