“窗口”,“宽度”和“顶部”具有局部值

时间:2018-09-12 13:00:45

标签: wpf binding snoop

我的主窗口的HeightLeftTopWidth通过样式绑定到它们各自的viewmodel属性。我可以确认视图模型中的这四个属性分别只设置为192019201181080

但是,当我启动该应用程序时,主窗口上的TopWidth属性设置为其他内容(Width将是1440和{{1} }是一个通常小于Top的随机数。是什么原因造成的?

这是我窥探应用程序时看到的内容。请注意300Top如何来自Width值源:

Before clear/reset

奇怪的是,当我右键单击Snoop中的那些属性并将其告诉“清除/重置”时,这些属性便开始表现出来。 Snoop在做什么来解决此问题?

After clear/reset

其他事实:

  • 在初始化主窗口时,LocalTop视图模型属性的吸气剂仅被调用一次。堆栈跟踪通过框架绑定初始化代码运行。
  • WidthTop视图模型属性的设置器只能从viewmodel构造函数中调用一次,因为它分别将这些属性设置为Width118
  • 这四个属性的绑定都是双向的。
  • 这些都不是导致视图属性更改/正确的原因:
    • 即使在视图完全加载后,仍在运行时更改关联的viewmodel属性。
    • 在视图上调用1080
    • 在视图上调用UpdateLayout()
    • 在视图上调用InvalidateArrange()
    • 在视图上调用InvalidateMeasure()
    • 在视图上调用InvalidateProperty(FrameworkElement.WidthProperty)
  • 我进行了搜索,没有任何地方接触到视图的InvalidateVisual()Top属性(样式绑定除外)的代码。

这是样式:

Bindings in the style

对不起,我不得不删除类型名称和其他一些内容-这是一个公司应用程序。如果有帮助,则主窗口/视图位于长继承行的结尾,并且Width是其伟大的祖父。我试图通过MVVM使主窗口更可重用-以前,这些布局属性是在视图的代码中设置的,而视图具有构造函数参数:'(这与为什么我需要键入样式有关,以及为什么该样式基于其他内容。但是继承的类型都无法操纵布局属性。

P.S。我见过其他人抱怨调整WPF Window的大小有多么困难。最常用的解决方案是绑定WindowMinWidth以及MaxWidth。当我这样做时,Width确实被强制设置为我想要的值,但是您无法调整窗口的大小,Width属性仍然具有其Width值源和{{ 1}}仍然不正确。

1 个答案:

答案 0 :(得分:0)

鉴于"[Top] cannot be set through a style",并给出了the complications with binding Window.Width,我以另一种方式解决了这个问题。

我创建了这个名为WindowLayout的附加属性,并将其绑定到我风格的viewmodel属性:

public static class WindowLayoutBehavior
{
    public static readonly DependencyProperty LayoutProperty = DependencyPropertyHelpers.RegisterAttached(
        (Window x) => GetLayout(x),
        new PropertyMetadata(HandleLayoutChanged));

    private static void HandleLayoutChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        if (!(d is Window window))
            return;
        if (!(e.NewValue is Rect rect))
            return;
        window.Height = rect.Height;
        window.Left = rect.Left;
        window.Top = rect.Top;
        window.Width = rect.Width;
    }

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static Rect GetLayout(Window window) =>
        window.GetValue(LayoutProperty) is Rect rect
            ? rect
            : default;

    public static void SetLayout(Window window, Rect rect) =>
        window.SetValue(LayoutProperty, rect);
}

DependencyPropertyHelpers.RegisterAttached是一种以您期望的方式创建附加属性的速记助手方法。

使用样式:

<Setter
    Property="WindowLayoutBehavior.Layout"
    Value="{Binding WindowLayout, Mode=OneWay}"/>

现在,当我监听应用程序时,HeightLeftTopWidth都显示为具有Local值源,并且它们在发生变化时会发生变化viewmodel属性更改,因此对我有用。