Alonzzo2
Alonzzo2

Reputation: 1009

C# WPF Behavior class, AssociatedObject is null after the UIElement was unloaded due to windows scaling change

I'm new to WPF, and trying to fix a bug with a draggable window.

I'm checking a bug in an app I maintain where we have a Behavior class, with which we implement a dragging mechanism. When I go to windows' display settings and change the scaling (100%/125%/150%/175%), windows seems to dispose the app's window and recreate it.
This is where the AssociatedObject member of the behavior class becomes null, so when the Loaded event is invoked again, I have no AssociatedObject to work with.

How can I get the new AssociatedObject? It seems like expected behavior since the UI element was recreated, but the behavior class is still 'alive' but can't do any work since it isn't familiar with the new UI element (If I understand things correctly, as I mentioned, I'm new to WPF)

Thanks!

Edit: adding a sample class

public class SetWindowSizeBehavior : Behavior<FrameworkElement>
{

    protected override void OnDetaching()
    {
        Console.WriteLine("detaching");
        base.OnDetaching();
    }

    protected override void OnAttached()
    {
        AssociatedObject.Unloaded += AssociatedObject_Unloaded;
        AssociatedObject.Loaded += AssociatedObject_Loaded;

        base.OnAttached();
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("");
        var a = AssociatedObject;
    }

    private void AssociatedObject_Unloaded(object sender, RoutedEventArgs e)
    {
        Detach();
    }
}

After I'm changing the scaling settings at the windows display settings menu, this is the call stack:
AssociatedObject_Unloaded
OnDetaching
AssociatedObject_Loaded <- this is where AssociatedObject becomes null

I hope the question is more clear now, and if not, would love to get some comments about missing info...

Upvotes: 0

Views: 1145

Answers (2)

Alonzzo2
Alonzzo2

Reputation: 1009

Eventually I used @DanielFr's idea and when I detected that the associatedObject is null (cause the base class Behavior sets it to null when the detach method is called) I used the sender object and:

if (AssociatedObject == null)
        {
            //If we got here then we didn't go through onAttached in this iteration
            Attach((FrameworkElement)sender);
        }

When FrameworkElement is my T in my Behavior class

Upvotes: 0

DanielFr
DanielFr

Reputation: 111

Can you try overriding the 'OnPropertyChanged' method

public class SetWindowSizeBehavior : Behavior<FrameworkElement>
{

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);
        if (AssociatedObject == null)
        {
            // so, let'save the value and then reuse it when OnAttached() called
            _value = e.NewValue as string;
            return;
        }

        if (e.Property == PasswordProperty)
        {
            if (!_skipUpdate)
            {
                _skipUpdate = true;
                AssociatedObject.Password = e.NewValue as string;
                _skipUpdate = false;
            }
        }
    }
    protected override void OnDetaching()
    {
        Console.WriteLine("detaching");
        base.OnDetaching();
    }

    protected override void OnAttached()
    {
        AssociatedObject.Unloaded += AssociatedObject_Unloaded;
        AssociatedObject.Loaded += AssociatedObject_Loaded;

        base.OnAttached();
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("");
        var a = AssociatedObject;
    }

    private void AssociatedObject_Unloaded(object sender, RoutedEventArgs e)
    {
        Detach();
    }
}

From here: https://stackoverflow.com/a/42312799/7779827

Upvotes: 1

Related Questions