保存WPF窗口和位置

时间:2010-05-17 04:25:51

标签: wpf windows

在WPF应用中保存窗口位置和大小的最佳方法是什么?

目前,我正在保存WPF应用程序的窗口大小和位置。以下是我处理的事件:

  1. SourceInitialized:已保存的信息已加载到窗口
  2. WindowClosing:当前信息保存到后备存储
  3. (我从一个例子中复制了这个)。

    问题是,当窗口最小化并恢复时,将检索最后一个WindowClosing的设置。

    现在,StateChanged事件在窗口最小化后触发,所以它似乎不是我需要的。

    由于

5 个答案:

答案 0 :(得分:9)

帮助您和您的用户,并使用LocationChanged事件和SizeChanged事件来保存当时的设置。如果进程异常退出并且设置没有得到保存(咳嗽......探险家......咳嗽......),那么没有什么比应用程序更容易烦恼了。

然后在保存设置之前检查以确保WindowState == Normal。显然,保存最小化或最大化窗口的位置毫无意义。

关于何时加载设置,您可以在InitializeComponent调用之后在构造函数中执行此操作,或者可以使用Initialized事件。没有真正的理由使用SourceInitialized事件,除非你直接对HWND做了一些不必要的事情。

答案 1 :(得分:1)

使用WindowInteropHelper对象获取窗口句柄并使用Screen.FromHandle方法获取窗口所在的实际屏幕。保存时请务必保存屏幕边界,以防它不再存在。

将屏幕恢复到以前的状态时需要注意的一点是,必须在创建窗口句柄后完成,因此在构造函数中无法执行此操作,否则在多个监视器情况下无法正常工作。尝试在SourceInitialized回调

上执行此操作

答案 2 :(得分:0)

你是通过数据绑定吗?这就是我做窗口大小和位置的方式。我通常有一个UserConfig.xml文件保存在用户配置文件中。然后我在那里创建元素,因为我在程序中对它们进行了数据处理。我有Application.xaml资源字典引用该文件,并且我想要设置为XPath的所有设置都是XML。然后我只在退出时保存内存中的xml文档。只有一个事件可以处理,没有乱七八糟,没有大惊小怪。

您可以将其扩展为包含与UI相关的任意数量的设置。添加管道设置有点困难,但并非如此。

答案 3 :(得分:0)

我有一个保存大小和状态的解决方案,你可以扩展它以保存位置。它是使用行为完成的。简单地绑定宽度和高度没有按预期工作,因为它会覆盖"正常"具有最大尺寸的州的大小。这就是if(state == normal)

等额外支票的原因

我的窗口Config上有一个DataContext属性。 您需要System.Windows.Interactivity的引用来执行此操作。

public class MainWindowSaveStateBehavior : Behavior<Window>
{
    public Config Config
    {
        get { return (Config)GetValue(ConfigProperty); }
        set { SetValue(ConfigProperty, value); }
    }

    public static readonly DependencyProperty ConfigProperty =
        DependencyProperty.Register("Config", typeof(Config), typeof(MainWindowSaveStateBehavior), new PropertyMetadata(Config_Changed));

    private static void Config_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var b = d as MainWindowSaveStateBehavior;
        if(e.NewValue != null) b.LoadSettings();
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SizeChanged += Window_SizeChanged;
        AssociatedObject.StateChanged += Window_StateChanged;
        LoadSettings();
    }

    bool _initialized = false;

    private void Window_StateChanged(object sender, EventArgs e)
    {
        SaveSettings();
    }

    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        SaveSettings();
    }

    private void LoadSettings()
    {
        if (Config == null) return;

        AssociatedObject.Width = Config.WindowWidth;
        AssociatedObject.Height = Config.WindowHeight;
        AssociatedObject.WindowState = Config.WindowState;

        _initialized = true;
    }

    private void SaveSettings()
    {
        if (Config == null || !_initialized) return;

        Config.WindowState = AssociatedObject.WindowState;
        if(AssociatedObject.WindowState == WindowState.Normal)
        {
            Config.WindowWidth = AssociatedObject.Width;
            Config.WindowHeight = AssociatedObject.Height;
        }
    }
}

在Xaml中,通过添加命名空间

来使用该行为
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:b="<the namespace your behavior lives in>"

然后附上行为

<i:Interaction.Behaviors>
    <b:MainWindowSaveStateBehavior Config="{Binding Config}" />
</i:Interaction.Behaviors>

然后,您必须在启动/关闭时在DataContext中加载并保存配置。

答案 4 :(得分:0)

我喜欢 CodeWarriors 的回答。我使用 TwoWay 绑定到应用设置:

Height="{Binding Source={x:Static p:Settings.Default}, Path=WindowHeight, Mode=TwoWay}"
Width="{Binding Source={x:Static p:Settings.Default}, Path=WindowWidth, Mode=TwoWay}"
Top="{Binding Source={x:Static p:Settings.Default}, Path=WindowTop, Mode=TwoWay}"
Left="{Binding Source={x:Static p:Settings.Default}, Path=WindowLeft, Mode=TwoWay}"

其中 p - 项目的属性命名空间。