【发布时间】:2017-02-24 13:11:40
【问题描述】:
我遇到了一个相当奇怪的问题。似乎只要窗口的 SizeToContent 设置为 Manual 并且尺寸和顶部/左侧属性是数据绑定的,Presentation Framework 就不会在显示窗口时更新窗口的位置。
我有一个对话框窗口控件,用于在其中显示其他用户控件,其行为应由 ViewModel 控制。我希望用SizeToContent.WidthAndHeight 和ResizeMode.NoResize 显示一些对话框,并将它们放在所有者窗口的中心。我希望在可以调整大小但以特定大小打开的对话框中显示的其他控件。
我做了一个测试项目只是为了隔离问题。这是我的对话框:
<Window x:Class="DialogTests.Dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DialogTests"
mc:Ignorable="d"
ResizeMode="CanResize"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner"
Width="{Binding Path=FormWidth, Mode=TwoWay}"
Height="{Binding Path=FormHeight, Mode=TwoWay}"
Top="{Binding Path=FormTop, Mode=TwoWay}"
Left="{Binding Path=FormLeft, Mode=TwoWay}"
Title="Dialog">
<StackPanel>
<Button Height="100">Button 1</Button>
<Button Width="100">Button 2</Button>
</StackPanel>
</Window>
public partial class Dialog : Window
{
public Dialog()
{
InitializeComponent();
this.DataContext = new DialogVm();
}
}
public class DialogVm : INotifyPropertyChanged
{
private double _formWidth;
private double _formHeight;
private double _formTop;
private double _formLeft;
public DialogVm()
{
FormWidth = 400;
FormHeight = 400;
}
public double FormWidth
{
get { return _formWidth; }
set
{
if (value.Equals(_formWidth)) return;
_formWidth = value;
OnPropertyChanged();
}
}
public double FormHeight
{
get { return _formHeight; }
set
{
if (value.Equals(_formHeight)) return;
_formHeight = value;
OnPropertyChanged();
}
}
public double FormTop
{
get { return _formTop; }
set
{
if (value.Equals(_formTop)) return;
_formTop = value;
OnPropertyChanged();
}
}
public double FormLeft
{
get { return _formLeft; }
set
{
if (value.Equals(_formLeft)) return;
_formLeft = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
将 Dialog 数据绑定到这些属性的原因是为了保存状态(尺寸和位置),以便在应使用这些先前值打开某些对话框的情况下使用它。
在我的主应用程序中,我只需按一个按钮即可打开对话框:
private void Button_Click(object sender, RoutedEventArgs e)
{
var dialog = new Dialog();
dialog.Owner = this;
dialog.ShowDialog();
}
如果你运行它,那么一切都会按预期运行。对话框调整大小以适合内容,并相对于主应用程序放置在中心。 FormWidth、FormHeight、FormTop 和 FormLeft 的设置器被调用。对于维度,它首先从构造函数中调用,然后由 PresentationFramework 调用。
但是,如果您返回对话框 xaml,并将 SizeToContent="WidthAndHeight" 更改为 SizeToContent="Manual",对话框将显示在屏幕的左上角 (0,0)。对话框的尺寸在视图模型构造器 (400 x 400) 中设置,并且不会再次被调用(如预期的那样)。问题是,FormTop 和 FormLeft 的 Setter 方法永远不会被调用。预期行为是 400x400 窗口应显示在所有者窗口的中心。
如果我更改 Dialog.xaml 以删除数据绑定,并显式设置维度,它会正常工作:
<Window x:Class="DialogTests.Dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DialogTests"
mc:Ignorable="d"
ResizeMode="CanResize"
SizeToContent="Manual"
WindowStartupLocation="CenterOwner"
Width="400"
Height="400"
Title="Dialog">
...
</Dialog>
这种行为是错误吗?还是我缺少什么?看起来很奇怪,只要将 SizeToContent 设置为 WidthAndHeight,或者我完全删除绑定并在 xaml 中设置属性,它就可以正常工作。
【问题讨论】: