My main window's Height, Left, Top, and Width are all bound to their respective viewmodel properties through a style. I can confirm that these four properties in the view model are only ever set to 1920, 1920, 118, 1080 respectively.
But when I launch the app, the Top and Width properties on the main window are set to something else (Width will be 1440 and Top will be a random number usually less than 300). What would cause this?
Here's what I see when I Snoop the app. Notice how Top and Width come from a Local Value Source:
Strangely, when I right-click on those properties in Snoop and tell it to "Clear/Reset", then those properties begin behaving. What is Snoop doing that fixes this?
Other facts:
- The getters for the
TopandWidthviewmodel properties are only called once while the main window is being initialized. The stack trace runs through framework binding initialization code. - The setters for the
TopandWidthviewmodel properties are only called once from the viewmodel constructor as it sets those properties to118and1080respectively. - The bindings for these four properties are all two-way.
- None of these things cause the view's properties to change/be correct:
- Changing the associated viewmodel properties at runtime, even after the view has been fully loaded.
- Calling
UpdateLayout()on the view. - Calling
InvalidateArrange()on the view. - Calling
InvalidateMeasure()on the view. - Calling
InvalidateProperty(FrameworkElement.WidthProperty)on the view. - Calling
InvalidateVisual()on the view.
- I have searched and searched and do not see any code anywhere touching the view's
ToporWidthproperties (other than the style bindings).
Here's the style:
Sorry I had to blank out type names and some other things—it's a company application. If it helps, the main window/the view is at the end of a long inheritance line with Window as its great-great grandaddy. I'm trying to make the main window more reusable by MVVM-ing it—formerly these layout properties were set in code-behind in the view, and the view had constructor parameters :'( That's related to why I need to key the style, and why the style is based on other stuff. But none of the inherited types manipulate layout properties.
P.S. I've seen other people complain about how hard it is to resize WPF's Window. The most commonly suggested solution is to bind MinWidth and MaxWidth as well as Width. When I do that then the Width is indeed forced to the value I want, but you can't resize the window, the Width property still has its Local Value Source, and Top is still incorrect.



Given that "[Top] cannot be set through a style", and given the complications with binding Window.Width, I solved this a different way.
I created this attached property called
WindowLayoutand bound it to a viewmodel property in my style:DependencyPropertyHelpers.RegisterAttachedis a shorthand helper method for creating the attached property in the way you might expect.Usage in the style:
Now when I Snoop the app,
Height,Left,Top, andWidthall show as havingLocalValue Sources, and they change when the viewmodel property changes, so that works for me.