How to find cause of WPF Window location change?

422 views Asked by At

Whenever I resume my computer from hibernation, it seems that my Window's location shifts to the top of the screen. I have the following to log my Window location:

        LocationChanged += (sender, args) =>
        {
            Logger.Info($"{Top},{SettingsHelper.Instance.Settings.WindowTop}");
        };

WindowTop is a property that is loaded into memory from a file that keeps track of where the Window last was before it was closed. Whenever this prints on startup, both values are correct as expected. However, after resuming from hibernation, this prints a 0 for the actual value, while the setting value is still the same. That eliminates an incorrect setting value being loaded from being the cause.

I'm also attempting to reload the settings whenever the computer resumes from hibernation:

    private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
    {
        if (e.Mode == PowerModes.Resume)
        {   
            LoadUiSettings();
        }
    }

    private void LoadUiSettings()
    {
        Left = SettingsHelper.Instance.Settings.WindowLeft;
        Top = SettingsHelper.Instance.Settings.WindowTop;
    }

This also does not resolve the issue. However, when I add in a MessageBox before the load, it'll show the Window at the incorrect location, then it'll properly load the settings and switch to the correct one. Since I moved my window away from the original location, I can see that on resume, it'll fix the location correctly, then somehow, after unlocking my computer, it'll move itself to Top = 0. Strange thing is that Left is not plagued by this issue at all. All the usages of both properties in the solution are identical. This does not happen with a vanilla WPF application, so I'm not really sure how to investigate this further. Strangely enough, this does not occur if I just lock the computer manually, and not by hibernating.

Is there a way to find out what is changing my Window's Top property somehow?

Edit: my workaround is to use SystemEvents.SessionSwitch and SessionSwitchReason.SessionUnlock and call LoadUiSettings from there, but that's still a bandaid around the actual problem. I'd still like to figure out what's causing it and solve it at the root.

Edit 2: If the Window isn't currently visible, setting it still does not change the actual position. I temporarily overrode the Visibility, then performed the following:

            while (Math.Abs(Top - SettingsHelper.Instance.Settings.WindowTop) > 0.1)
            {
                Top = SettingsHelper.Instance.Settings.WindowTop;
            }

I see the Window show up for a split second while it's waiting to be adjusted, then after it disappears again, and I toggle the visibility manually through the UI, it's at the top again. Toggling it manually when it's already in the correct location does not yield this behavior.

1

There are 1 answers

3
Alexander Bell On

Pertinent to your specific question (i.e. finding the CAUSE of the problem, but not asking for the solution), the answer may be found using the following code snippet to perform analysis of WPF Window position change corresponding to PowerModeChange event:

SystemEvents.PowerModeChanged += OnPowerChange;

private void OnPowerChange(object s, PowerModeChangedEventArgs e) 
{
    switch ( e.Mode ) 
    {
        case PowerModes.Resume:
        // Log the position as it's done in your example
        Logger.Info ("Mode Change: Resume");
        Logger.Info($"{Top},{SettingsHelper.Instance.Settings.WindowTop}");
        break;
        case PowerModes.Suspend:
        Logger.Info ("Mode Change: Suspend");
        Logger.Info($"{Top},{SettingsHelper.Instance.Settings.WindowTop}");
        break;
    }
}

Upon finding the root cause of your problem (namely, which event causes the Window dislocation), you may develop relatively simply fix, like for e.g. re-positioning the Window on PowerModes.Resume event.

Hope this may help.