WPF窗口最大化时绑定宽度触发两次的解决方法
这个问题其实是Catel框架的Window控件默认行为导致的——它会自动保存和恢复窗口的位置与尺寸,在最大化窗口时,这个机制会干扰你的双向绑定:
- 窗口开始最大化,系统会把窗口尺寸设为屏幕工作区大小,此时你的
W和H会被正确更新为这个值; - 紧接着Catel会把绑定的属性重置为它之前保存的非最大化状态下的原始尺寸,这就是你看到第二次更新变回旧值的原因。
下面给你两种可行的解决思路,根据你的需求选择:
方案1:关闭Catel的窗口状态自动保存(最简单)
如果你不需要Catel帮你记住窗口上次关闭时的位置和尺寸,直接在XAML的Catel Window上添加SaveWindowPositionAndSize="False"属性即可:
<catel:Window x:Class="WPFTestApplication1.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:catel="http://schemas.catelproject.com" ResizeMode="CanResize" Width="{Binding W,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="{Binding H,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" MinHeight="400" MinWidth="600" SaveWindowPositionAndSize="False"> <!-- 添加这一行 --> <!-- 原有内容不变 --> </catel:Window>
这样Catel就不会再干预你的尺寸绑定,最大化时W和H只会更新一次,对应窗口的实际最大化尺寸。
方案2:保留Catel状态管理,手动处理最大化尺寸
如果你需要Catel记住窗口的非最大化状态尺寸,那可以通过监听窗口的StateChanged事件,在ViewModel中区分窗口状态,获取正确的尺寸:
修改你的MainWindowViewModel,添加窗口状态监听逻辑:
public class MainWindowViewModel : ViewModelBase { public MainWindowViewModel() { } public override string Title { get { return "WPFTestApplication1"; } } protected override async Task InitializeAsync() { await base.InitializeAsync(); // 获取关联的View并监听StateChanged事件 if (View is Window window) { window.StateChanged += OnWindowStateChanged; } } private void OnWindowStateChanged(object sender, EventArgs e) { if (sender is Window window) { if (window.WindowState == WindowState.Maximized) { // 最大化时,使用窗口的ActualWidth/ActualHeight(这是真实的屏幕工作区尺寸) var actualWidth = window.ActualWidth; var actualHeight = window.ActualHeight; // 在这里用actualWidth和actualHeight处理你的内容缩放逻辑 Console.WriteLine($"当前最大化尺寸:{actualWidth} x {actualHeight}"); } else { // 非最大化状态时,W和H的值是正确的 Console.WriteLine($"当前窗口尺寸:{W} x {H}"); } } } protected override async Task CloseAsync() { // 记得取消事件订阅,避免内存泄漏 if (View is Window window) { window.StateChanged -= OnWindowStateChanged; } await base.CloseAsync(); } // 原有W和H属性不变 public double H { get { return GetValue<double>(HProperty); } set { SetValue(HProperty, value); Console.WriteLine(value); } } public static readonly PropertyData HProperty = RegisterProperty(nameof(H), typeof(double), null); public double W { get { return GetValue<double>(WProperty); } set { SetValue(WProperty, value); Console.WriteLine(value); } } public static readonly PropertyData WProperty = RegisterProperty(nameof(W), typeof(double), null); }
这种方式下,Catel依然会保存你的非最大化尺寸,但你可以在最大化时直接取窗口的实际渲染尺寸,避免被绑定的旧值干扰。
内容的提问来源于stack exchange,提问作者K.Zuiderduin
相关产品推荐
相关产品推荐

