Dante
Dante

Reputation: 3316

How to modify inner control property by setting container control dependency property?

I am creating a control in WPF which have inside a label and I have created a dependency property in order to modify the label's visibility property.

My problem is that I cant find a way to change my label's visibility property at the same time my dependency property is assigned.

My code is as below:

public static readonly DependencyProperty captionVisibleProperty = DependencyProperty.Register(
                                                                            "CaptionVisible",
                                                                            typeof(bool),
                                                                            typeof(MyCustomControl));

    public bool CaptionVisible
    {
        get
        {
            return (bool)GetValue(captionVisibleProperty);
        }
        set
        {
            SetValue(captionVisibleProperty, value);
            ShowCaption();
        }
    }

    private void ShowCaption()
    {
        if (CaptionVisible)
        {
            captionLabel.Visibility = System.Windows.Visibility.Visible;
        }
        else
        {
            captionLabel.Visibility = System.Windows.Visibility.Collapsed;
        }
    }

As you can see I have tried to call my ShowCaption() method when my property is set, but nothing happens.

So, what I am supposed to do in order to get it done?

Hope someone can help me. Thank you in advance.

Upvotes: 0

Views: 301

Answers (2)

Dante
Dante

Reputation: 3316

I have found a solution to this problem:

If you need to link a nested control dependency property to a container control dependency property you can do this:

     public static readonly DependencyProperty captionLabelVisibilityProperty = DependencyProperty.Register(
                                                                                    "CaptionVisibility",
                                                                                    typeof(Visibility),
                                                                                    typeof(MyContainerControl),
                                                                                    new FrameworkPropertyMetadata(
                                                                                        VisibilityPropertyChangedCallback));

    public Visibility CaptionVisibility
    {
        get
        { return (Visibility)GetValue(captionLabelVisibilityProperty); }

        set
        { SetValue(captionLabelVisibilityProperty, value); }
    }

    private static void VisibilityPropertyChangedCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
    {
        MyContainerControl myContainerControlInstance = (MyContainerControl)controlInstance;
        myContainerControlInstance.myLabel.Visibility = (Visibility)args.NewValue;
    }

Upvotes: 0

Sean U
Sean U

Reputation: 6850

ShowCaption() shouldn't be necessary. Instead, just bind the label's Visibility property to your CaptionVisible property in xaml. It's also best to follow the Model-View-ViewModel design pattern for keeping your code organized. This means putting the logic for controlling your user interface (the View) in separate ViewModel classes, and then assigning ViewModel to that View's DataContext property.

That will make the binding a lot easier. Referencing properties that belong to user interface elements can sometimes be a bit of a hassle in WPF. By contract, WPF's bindings system was specifically designed to make it easy to get at the contents of a user interface element's DataContext.

You'll also need to use the handy-dandy BooleanToVisiblityConverter to make the binding work, since the Visibility property's type isn't bool. I like to put it in in the window's (or control's) resource dictionary for easy access:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>


<Label Visibility="{Binding Path=CaptionVisible, 
                            Converter={StaticResource BooleanToVisibilityConverter}}"> 
    <!-- label content -->
</Label>

As a side note, unless CaptionVisible is going to be the target of a binding, making it a dependency property is overkill. In this binding it's only the source, so just implementing INotifyPropertyChanged would be sufficient:

class MyViewModel : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private bool _captionVisible;
    public bool CaptionVisible
    {
        get { return _captionVisible; }
        set
        {
            if(_captionVisible != value)
            {
                _captionVisible = value;
                RaisePropertyChanged("CaptionVisible");
            }
        }
    }
}

Upvotes: 1

Related Questions