绑定窗口高度和宽度出现问题

28

当我尝试将窗口的高度和宽度绑定到我的视图模型中的属性时,遇到了一些问题。这是一个小的示例应用程序,以说明这个问题。以下是app.xaml.xs中的代码:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
       base.OnStartup(e);
        MainWindow mainWindow = new MainWindow();
        MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
        mainWindow.DataContext = mainWindowViewModel;
        mainWindow.Show();
    }
}

这是 MainWindow.xaml:

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="{Binding WindowHeight}" 
        Width="{Binding WindowWidth}"
        BorderThickness="{Binding WindowBorderThickness}">
</Window>

这是视图模型:

public class MainWindowViewModel
{
    public int WindowWidth { get { return 100; } }
    public int WindowHeight { get { return 200; } }
    public int WindowBorderThickness { get { return 8; } }
}

程序启动时调用 WindowHeight 和 WindowBorderThickness 的 getter 方法(但不包括 WindowWidth ),这样窗口的高度和边框会正确设置,但宽度不会。

然后我添加了一个按钮,触发所有属性的 PropertyChanged,因此视图模型现在如下所示:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void TriggerPropertyChanges()
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("WindowWidth"));
            PropertyChanged(this, new PropertyChangedEventArgs("WindowHeight"));
            PropertyChanged(this, new PropertyChangedEventArgs("WindowBorderThickness"));
        }

    }

    public ICommand ButtonCommand { get { return new RelayCommand(delegate { TriggerPropertyChanges(); }); } }

    public int WindowWidth { get { return 100; } }
    public int WindowHeight { get { return 200; } }
    public int WindowBorderThickness { get { return 8; } }
}

现在,当我点击按钮时,WindowBorderThickness的getter被调用了,但是WindowWidth和WindowHeight的getter却没有被调用。这一切对我来说似乎非常奇怪和不一致。我错过了什么吗?


1
你在调试时的输出窗口中有任何警告吗? - Drake
10个回答

57

试试使用双向绑定,这对我有用:

Width="{Binding Path=xExt, Mode=TwoWay}"

当我从代码中设置DataContext时(就像OP所做的那样),这种方法不起作用。但是,如果我在XAML中设置它,它就能很好地工作。 - undefined

13

我曾经遇到过同样的问题,发现在XAML中写入高度或宽度时,Binding只会对第一个属性有效。 解决方法是将Binding模式设置为“TwoWay”:

我所制作的项目使用的是MS Studio 2010和.NET 4.0。


12

我将尝试回答自己的问题。绑定是有效的,但我们不能确定布局系统是否要求窗口的宽度属性。

根据MSDN

如果此元素是另一个元素中的子元素,则将该属性设置为值实际上仅是建议值。布局系统以及父元素的特定布局逻辑将在布局过程中将值用作非绑定输入。实际上,FrameworkElement 几乎总是其他某个元素的子元素;即使在 Window 上设置 Height。(对于 Window,该值在底层应用程序模型建立创建托管应用程序的 Hwnd 的基本渲染假设时使用。)

一种看起来有效的解决方案是将 WindowWidth 属性绑定到 MinWidth 和 MaxWidth,以及 Width。至少在我上面使用的测试场景中,其中一个属性将被检索。


6

好的,

我遇到了同样的问题,在通过XAML将窗口尺寸(最小、最大、正常)正确绑定到我的视图模型中时无法成功。

我不知道为什么,但是如果你通过代码而不是通过XAML来进行这些绑定,就可以毫无问题地实现所有这些绑定。

这是我的C#代码,它起作用:

this.SetBinding(Window.WidthProperty, new Binding("Width") { Source = MyViewModel, Mode=BindingMode.TwoWay });
this.SetBinding(Window.HeightProperty, new Binding("Height") { Source = MyViewModel, Mode=BindingMode.TwoWay });
this.SetBinding(Window.MaxWidthProperty, new Binding("MaxWidth") { Source = MyViewModel });
this.SetBinding(Window.MaxHeightProperty, new Binding("MaxHeight") { Source = MyViewModel });
this.SetBinding(Window.MinWidthProperty, new Binding("MinWidth") { Source = MyViewModel });
this.SetBinding(Window.MinHeightProperty, new Binding("MinHeight") { Source = MyViewModel });

奇怪的是,它只在代码中起作用,而不在XAML中起作用。更奇怪的是,它默认绑定mMin和Max尺寸的TwoWay,但对于Normal尺寸,则必须指定“Mode=BindingMode.TwoWay”。

这应该是微软需要纠正的一个bug...


1
同样的问题。在XAML中不起作用,但在代码中可以。在我的情况下,绑定到“Width”和“Height”就足够了。 - Martin Schneider

5
此外,您可以使用SizeToContent="WidthAndHeight"MinHeightMinWidth一起使用,这样就不需要额外调用MaxHeightMaxWidth

2
我已经使用以下代码解决了这个问题。我希望它能帮助到某些人。
重要提示:WPF中的动态绑定始终仅适用于属性,而不适用于变量。
在.xaml.cs文件中声明一个全局公共属性,如下所示:
public Double DynamicHeight { get; set; }

// Set DynamicHeight property value in Window_Loaded or any other event
private void Window_Loaded(object sender, RoutedEventArgs e)
{
     DynamicHeight = 200;
}

在.xaml文件中设置动态高度,如下所示:

<Grid Height="{Binding DynamicHeight, Mode=TwoWay}">
</Grid>

如果您认为这个回答对您有帮助,请投票支持。谢谢!


1

我不确定你的具体实现,但我写了一个例子,可能会有所帮助。

XAML

<Window x:Name="MainWindow"
    x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" 
    MinWidth="200"
    MinHeight="100"
    Width="{Binding ElementName=MainWindow, Path=WindowWidth}"
    Height="{Binding ElementName=MainWindow, Path=WindowHeight}">
    <Grid>
        <Slider 
            x:Name="slWidth" 
            Value="{Binding ElementName=MainWindow, Path=WindowWidth, Mode=TwoWay}"
            Minimum="200"
            Maximum="1600"
            Height="23" HorizontalAlignment="Left" Margin="56,22,0,0" VerticalAlignment="Top" Width="61" />
        <Label 
            Content="Width" 
            Height="28" 
            HorizontalAlignment="Left" 
            Margin="12,22,0,0" 
            Name="Label1" 
            VerticalAlignment="Top" />
        <Slider 
            x:Name="slHeight" 
            Value="{Binding ElementName=MainWindow, Path=WindowHeight, Mode=TwoWay}"
            Minimum="100"
            Maximum="800"
            Height="23" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="61" Margin="56,51,0,0" />
        <Label 
            Content="Height" 
            Height="28" 
            HorizontalAlignment="Left"              
            VerticalAlignment="Top" Margin="12,46,0,0" />
    </Grid>
</Window>

代码

Class MainWindow

    Public Shared ReadOnly WindowWidthProperty As DependencyProperty = _
                           DependencyProperty.Register("WindowWidth", _
                           GetType(Integer), GetType(MainWindow), _
                           New FrameworkPropertyMetadata(Nothing))

    Public Shared ReadOnly WindowHeightProperty As DependencyProperty = _
                         DependencyProperty.Register("WindowHeight", _
                         GetType(Integer), GetType(MainWindow), _
                         New FrameworkPropertyMetadata(Nothing))

    Public Property WindowWidth As Integer
        Get
            Return CInt(GetValue(WindowWidthProperty))
        End Get
        Set(ByVal value As Integer)
            SetValue(WindowWidthProperty, value)
        End Set
    End Property

    Public Property WindowHeight As Integer
        Get
            Return CInt(GetValue(WindowHeightProperty))
        End Get
        Set(ByVal value As Integer)
            SetValue(WindowHeightProperty, value)
        End Set
    End Property


End Class

C#代码

public readonly DependencyProperty WindowWidthProperty = DependencyProperty.Register("WindowWidth", typeof(Double), typeof(MainWindow), new FrameworkPropertyMetadata());
public readonly DependencyProperty WindowHeightProperty = DependencyProperty.Register("WindowHeight", typeof(Double), typeof(MainWindow), new FrameworkPropertyMetadata());

public double WindowWidth {
    get { return Convert.ToDouble(this.GetValue(WindowWidthProperty)); }
    set { this.SetValue(WindowWidthProperty, value); }
}

public double WindowHeight {
    get { return Convert.ToDouble(this.GetValue(WindowHeightProperty)); }
    set { this.SetValue(WindowHeightProperty, value); }
}

1
这里的基本区别在于,您绑定到了MainWindow本身,而我则绑定到了一个单独的视图模型。出于某种原因,这似乎会产生差异。如果我使用您的滑块来实现我的视图模型,它将无法工作(除非我也像在我的答案中所述那样绑定到MinHeight和MaxHeight)。无论如何,感谢您提供的示例。 - D.H.

1

绑定到MinWidth和MinHeight是正确的。此外,如果您的动态将同时扩大或缩小窗口的大小,则需要绑定到MaxWidth和MaxHeight。


0
Height="{DynamicResource {x:Static SystemParameters.PrimaryScreenHeightKey}}" Width="{DynamicResource {x:Static SystemParameters.PrimaryScreenWidthKey}}"

在我的端上运行良好。


-1

只需添加Mode = TwoWay Width = "{Binding WindowWidth,UpdateSourceTrigger = PropertyChanged,Mode = TwoWay,FallbackValue = 350}"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接