0
votes

I have the following DependencyProperty in a custom control:

  public bool HasConnection
    {
        get { return (bool)GetValue(HasConnectionProperty); }
        set { SetValue(HasConnectionProperty, value); }
    }

    public static readonly DependencyProperty HasConnectionProperty =
        DependencyProperty.Register(
        "HasConnection",
        typeof(bool),
        typeof(NetworkNode),
        new FrameworkPropertyMetadata(
            false,
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            new PropertyChangedCallback(HasConnectionChangedCallBack)));


    private static void HasConnectionChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        NetworkNode nn = (NetworkNode)d;
        Ellipse el = nn.GetTemplateChild("PART_inner") as Ellipse;
        if (el.PART_inner.Visibility == ...) <-- exception el is null
            //..code..
    }

Runs fine, but if I change the property in Properties panel of my custom control, at run time throws an exception: Object reference not set to an instance of an object.

enter image description here

Edit1:

Forgot to add one line of code in the post Ellipse el = nn.GetTemplateChild("PART_inner") as Ellipse;

Edit2:

Creating a BooleanToVisibilityConverter and using Binding in Generic.xaml works, but the HasConnectionChangedCallBack method is now empty/useless.

Visibility="{Binding HasConnection, Converter={StaticResource BooleanToVisibiltyConverter}, RelativeSource={RelativeSource TemplatedParent}}"

Edit3:

Found a posible fix. The property callback method is called first then the OnApplyTemplate() method, so no more exceptions thrown or error in xaml.

In OnApplyTemplate() I add

 if (this.HasConnection)
            PART_inner.Visibility = System.Windows.Visibility.Visible;
        else
            PART_inner.Visibility = System.Windows.Visibility.Hidden;
2
I don't think there is enough information there to really answer your question. What is a network node? What is PART_Inner?sircodesalot
Its a custom control.Runs ok if i dont touch the property in a wpf application. If a set the HasConnection = "True", in xaml, at run time throws an excetion.iulian3000

2 Answers

0
votes

Do this

private static void HasConnectionChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue == null) 
        return;

    NetworkNode nn = (NetworkNode)d;

    if (nn == null || nn.Part_inner == null ) 
        return;

    if (nn.PART_inner.Visibility == ...) <-- exception
        //..code..
}
0
votes

The reason for the exception is that when the property is set through the XAML parser, the content of the UserControl has not been instantiated.

The XAML parser works its way from top to bottom through the XAML. A UserControl is just a shortcut for the XAML that defines it, so, at the time when the XAML parser sets HasConnection=True on the outer control, its content has not yet been instantiated, so PART_Inner doesn't yet exist.

The solution is to define the relationship between HasConnection and whatever depends on it in the UserControl in a way that keeps the instantiation sequence in mind. For example, if PART_Inner is a UserControl, you could search for its parent of type NetworkNode in its Loaded event, so that HasConnection can be evaluated then. This is probably the solution which requires the least changes to your existing code. Leave the change handler as it is now, including the safety code, and add logic to the contained control which reads the start value from its ancestor.

Other options would be to not use a DependencyPropertyChanged callback at all, but create a Binding on the Visibility property using a RelativeSource typed FindAncestor and a BooleanToVisibilityConverter. Still another idea would be to use a Trigger.