.NET WPF记住窗口大小在会话之间

103

基本上,当用户调整我的应用程序窗口的大小时,我希望在下次打开应用程序时该应用程序保持相同的大小。

起初,我考虑处理SizeChanged事件并保存高度和宽度,但我认为一定有更简单的解决方案。

这是一个非常简单的问题,但我找不到简单的解决方案。


2
请注意,如果您正在恢复大小和位置(如下面大多数代码示例所示),则需要处理某人拔掉上次呈现窗口的监视器的边缘情况,以避免在屏幕外呈现窗口。 - Omer Raviv
@OmerRaviv 你找到一个考虑边缘情况的例子了吗? - Andrew Truckle
我声望太低,无法添加评论,因此我创建了这个新答案。我使用与Lance Cleveland相同的解决方案,包括设置RobJohnson,但如果您将其用于子窗口并希望同时打开更多窗口,则不起作用... - AelanY
13个回答

128

将值保存在 user.config 文件中。

你需要在 Properties 文件夹中创建设置文件中的值。创建五个值:

  • Top,类型为 double
  • Left,类型为 double
  • Height,类型为 double
  • Width,类型为 double
  • Maximized,类型为 bool - 用于保存窗口是否最大化。如果要存储更多信息,则需要不同类型或结构。

将前两个值初始化为 0,将后两个值初始化为应用程序的默认大小,并将最后一个值初始化为 false。

创建 Window_OnSourceInitialized 事件处理程序并添加以下内容:

this.Top = Properties.Settings.Default.Top;
this.Left = Properties.Settings.Default.Left;
this.Height = Properties.Settings.Default.Height;
this.Width = Properties.Settings.Default.Width;
// Very quick and dirty - but it does the job
if (Properties.Settings.Default.Maximized)
{
    WindowState = WindowState.Maximized;
}

注意: 设置窗口位置应该在窗口的 on source initialised 事件中完成,而不是构造函数中完成。否则,如果你将窗口最大化到第二个监视器上,在主监视器上它将始终重新启动最大化,并且你将无法访问它。

创建一个 Window_Closing 事件处理程序并添加以下代码:

if (WindowState == WindowState.Maximized)
{
    // Use the RestoreBounds as the current values will be 0, 0 and the size of the screen
    Properties.Settings.Default.Top = RestoreBounds.Top;
    Properties.Settings.Default.Left = RestoreBounds.Left;
    Properties.Settings.Default.Height = RestoreBounds.Height;
    Properties.Settings.Default.Width = RestoreBounds.Width;
    Properties.Settings.Default.Maximized = true;
}
else
{
    Properties.Settings.Default.Top = this.Top;
    Properties.Settings.Default.Left = this.Left;
    Properties.Settings.Default.Height = this.Height;
    Properties.Settings.Default.Width = this.Width;
    Properties.Settings.Default.Maximized = false;
}

Properties.Settings.Default.Save();

如果用户在应用程序关闭时将显示区域缩小 - 例如断开了屏幕或更改了屏幕分辨率 - 则此操作将失败,因此您应该在应用值之前添加检查以确保所需位置和大小仍然有效。


5
实际上,作用域为“用户”的设置不会保存在Program Files的app.config文件中,而是保存在用户应用程序数据目录中的user.config文件中。所以这不是一个问题... - Thomas Levesque
8
实际上,您可以将“WindowState”添加到设置中。选择类型->浏览->PresentationFramework->System.Windows->WindowState :) - MartyIX
2
就我个人而言,我也会在大小更改处理程序中执行此操作,以防应用程序崩溃。虽然未处理的异常处理很少出现,但为什么要惩罚用户在它们神秘地发生时失去大小/位置呢? - Thomas
8
这段代码存在一个漏洞,即如果用户将窗口打开在第二个屏幕上,然后断开连接该屏幕与电脑的连接,下次打开窗口时,它会显示在屏幕外。如果窗口是模态的,则用户将无法与应用程序交互,并且不会理解发生了什么。你需要添加一个边界检查,使用Window.GetScreen()方法,并在将屏幕坐标转换为DPI相关值之后进行 - Omer Raviv
4
@OmerRaviv - 这不是一个 bug,而是一个限制 :) 说真的- 我没有涉及问题的那个方面。 - ChrisF
显示剩余11条评论

81

实际上你不需要使用代码后台来实现这个(除了保存设置)。你可以使用自定义标记扩展将窗口大小和位置绑定到设置中,就像这样:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="Window1"
        Height="{my:SettingBinding Height}"
        Width="{my:SettingBinding Width}"
        Left="{my:SettingBinding Left}"
        Top="{my:SettingBinding Top}">

您可以在此处找到此标记扩展的代码: http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/


4
我更喜欢这个答案,比被选中的采纳的答案好。做得好。 - moswald
6
+1 - 我喜欢绑定和扩展的使用!如果您将WindowState添加到绑定设置中,它提供了完整的功能。或者,如果您在DataContext中有用户设置可用,可以使用类似于 {Binding Settings.Height} 的东西。 - Matt DeKrey
当用户关闭最大化的窗口时,这种方法会出现问题。 - Vinicius Rocha
让操作系统来完成繁重的工作...(请参见安迪的回答) - Rafael Rivera
4
当人们使用两个显示器时,可能会出现负坐标,如果他们更改了显示器配置,则这些值将不再有效。 - Andrew Truckle
显示剩余6条评论

38

虽然你可以“自己动手”并手动将设置保存在某个地方,而且通常可以正常工作,但很容易处理不正确的所有情况。更好的方法是让操作系统替你完成这项工作,通过在退出时调用GetWindowPlacement(),在启动时调用SetWindowPlacement()。它处理了可能发生的所有奇怪的边界情况(多个监视器,在最大化窗口时关闭窗口时保存正常大小等),因此您无需处理。

这个MSDN样例展示了如何在WPF应用程序中使用它们。该样例并不完美(窗口将在第一次运行时以最小化的方式从左上角开始,而且设置设计器保存的值类型为WINDOWPLACEMENT存在一些奇怪的行为),但至少可以帮助你入门。


不错的解决方案。但是我刚刚发现GetWindowPlacement / SetWindowPlacement不支持Aero Snap。 - Mark Bell
1
@RandomEngy基于此发布了一个改进的答案。 - Stéphane Gourichon

30

Thomas发布的“长形式”绑定几乎不需要编码,只需确保您有名称空间绑定:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:p="clr-namespace:WpfApplication1.Properties"
        Title="Window1"
        Height="{Binding Source={x:Static p:Settings.Default}, Path=Height, Mode=TwoWay}"
        Width="{Binding Source={x:Static p:Settings.Default}, Path=Width, Mode=TwoWay}"
        Left="{Binding Source={x:Static p:Settings.Default}, Path=Left, Mode=TwoWay}"
        Top="{Binding Source={x:Static p:Settings.Default}, Path=Top, Mode=TwoWay}">

然后在代码后端进行简化:

private void frmMain_Closed(object sender, EventArgs e)
{
    Properties.Settings.Default.Save();
}

我选择了这个解决方案,但只有在窗口状态为正常时才保存设置,否则从最大化模式中退出可能会很麻烦。 - David Sykes
7
+1 我也使用过这个,@DavidSykes - 添加另一个窗口状态的设置似乎足够好了,例如 WindowState="{Binding Source={x:Static properties:Settings.Default}, Path=WindowState, Mode=TwoWay}" - RobJohnson
@RobJohnson 我尝试了你的建议,非常好用,谢谢。 - David Sykes
我在 Settings.Default.PropertyChanged += (s, e) => Settings.Default.Save() 上进行了优化,并添加了一些延迟 WindowState="{Binding MainWindow_WindowState, Source={x:Static properties:Settings.Default}, Delay=250, Mode=TwoWay}" 以便节省 SSD。 - Palatis
如果您在第二个显示器上最大化窗口,则在启动时不会在同一显示器上还原。 - Julien

5

另一种方法是将以下方法应用到您的项目中 (参见源代码)。在您的主窗口头部插入WindowSettings.Save="True"

<Window x:Class="YOURPROJECT.Views.ShellView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Services="clr-namespace:YOURNAMESPACE.Services" 
    Services:WindowSettings.Save="True">

其中WindowSettings的定义如下:

using System;
using System.ComponentModel;
using System.Configuration;
using System.Windows;

namespace YOURNAMESPACE.Services
{
/// <summary>
///   Persists a Window's Size, Location and WindowState to UserScopeSettings
/// </summary>
public class WindowSettings
{
    #region Fields

    /// <summary>
    ///   Register the "Save" attached property and the "OnSaveInvalidated" callback
    /// </summary>
    public static readonly DependencyProperty SaveProperty = DependencyProperty.RegisterAttached("Save", typeof (bool), typeof (WindowSettings), new FrameworkPropertyMetadata(OnSaveInvalidated));

    private readonly Window mWindow;

    private WindowApplicationSettings mWindowApplicationSettings;

    #endregion Fields

    #region Constructors

    public WindowSettings(Window pWindow) { mWindow = pWindow; }

    #endregion Constructors

    #region Properties

    [Browsable(false)] public WindowApplicationSettings Settings {
        get {
            if (mWindowApplicationSettings == null) mWindowApplicationSettings = CreateWindowApplicationSettingsInstance();
            return mWindowApplicationSettings;
        }
    }

    #endregion Properties

    #region Methods

    public static void SetSave(DependencyObject pDependencyObject, bool pEnabled) { pDependencyObject.SetValue(SaveProperty, pEnabled); }

    protected virtual WindowApplicationSettings CreateWindowApplicationSettingsInstance() { return new WindowApplicationSettings(this); }

    /// <summary>
    ///   Load the Window Size Location and State from the settings object
    /// </summary>
    protected virtual void LoadWindowState() {
        Settings.Reload();
        if (Settings.Location != Rect.Empty) {
            mWindow.Left = Settings.Location.Left;
            mWindow.Top = Settings.Location.Top;
            mWindow.Width = Settings.Location.Width;
            mWindow.Height = Settings.Location.Height;
        }
        if (Settings.WindowState != WindowState.Maximized) mWindow.WindowState = Settings.WindowState;
    }

    /// <summary>
    ///   Save the Window Size, Location and State to the settings object
    /// </summary>
    protected virtual void SaveWindowState() {
        Settings.WindowState = mWindow.WindowState;
        Settings.Location = mWindow.RestoreBounds;
        Settings.Save();
    }

    /// <summary>
    ///   Called when Save is changed on an object.
    /// </summary>
    private static void OnSaveInvalidated(DependencyObject pDependencyObject, DependencyPropertyChangedEventArgs pDependencyPropertyChangedEventArgs) {
        var window = pDependencyObject as Window;
        if (window != null)
            if ((bool) pDependencyPropertyChangedEventArgs.NewValue) {
                var settings = new WindowSettings(window);
                settings.Attach();
            }
    }

    private void Attach() {
        if (mWindow != null) {
            mWindow.Closing += WindowClosing;
            mWindow.Initialized += WindowInitialized;
            mWindow.Loaded += WindowLoaded;
        }
    }

    private void WindowClosing(object pSender, CancelEventArgs pCancelEventArgs) { SaveWindowState(); }

    private void WindowInitialized(object pSender, EventArgs pEventArgs) { LoadWindowState(); }

    private void WindowLoaded(object pSender, RoutedEventArgs pRoutedEventArgs) { if (Settings.WindowState == WindowState.Maximized) mWindow.WindowState = Settings.WindowState; }

    #endregion Methods

    #region Nested Types

    public class WindowApplicationSettings : ApplicationSettingsBase
    {
        #region Constructors

        public WindowApplicationSettings(WindowSettings pWindowSettings) { }

        #endregion Constructors

        #region Properties

        [UserScopedSetting] public Rect Location {
            get {
                if (this["Location"] != null) return ((Rect) this["Location"]);
                return Rect.Empty;
            }
            set { this["Location"] = value; }
        }

        [UserScopedSetting] public WindowState WindowState {
            get {
                if (this["WindowState"] != null) return (WindowState) this["WindowState"];
                return WindowState.Normal;
            }
            set { this["WindowState"] = value; }
        }

        #endregion Properties
    }

    #endregion Nested Types
}
}

5

有一个NuGet项目 RestoreWindowPlace,你可以在GitHub上找到它,这个项目可以为你完成所有操作,并将信息保存在XML文件中。

要在窗口上使用它,只需调用以下代码:

((App)Application.Current).WindowPlace.Register(this);

在应用程序中,你需要创建一个管理窗口的类。有关更多信息,请参见上面的GitHub链接。


2
这个软件包非常好用,而且它也能正确处理最小化的窗口和断开连接的显示器。在我看来,这应该是被采纳的答案。 - Urs Meili

4

我基于RandomEngys出色的回答制作了一种更通用的解决方案。它将位置保存到正在运行的文件夹中,您不需要为每个新窗口创建新属性。这个解决方案对我来说非常好,代码很少。

using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Xml;
using System.Xml.Serialization;

namespace WindowPlacementNameSpace
{

    // RECT structure required by WINDOWPLACEMENT structure
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public RECT(int left, int top, int right, int bottom)
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }
    }

    // POINT structure required by WINDOWPLACEMENT structure
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

    // WINDOWPLACEMENT stores the position, size, and state of a window
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct WINDOWPLACEMENT
    {
        public int length;
        public int flags;
        public int showCmd;
        public POINT minPosition;
        public POINT maxPosition;
        public RECT normalPosition;
    }

    public static class WindowPlacement
    {
        private static readonly Encoding Encoding = new UTF8Encoding();
        private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(WINDOWPLACEMENT));

        [DllImport("user32.dll")]
        private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);

        [DllImport("user32.dll")]
        private static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);

        private const int SW_SHOWNORMAL = 1;
        private const int SW_SHOWMINIMIZED = 2;

        private static void SetPlacement(IntPtr windowHandle, string placementXml)
        {
            if (string.IsNullOrEmpty(placementXml))
            {
                return;
            }

            byte[] xmlBytes = Encoding.GetBytes(placementXml);

            try
            {
                WINDOWPLACEMENT placement;
                using (MemoryStream memoryStream = new MemoryStream(xmlBytes))
                {
                    placement = (WINDOWPLACEMENT)Serializer.Deserialize(memoryStream);
                }

                placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
                placement.flags = 0;
                placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd);
                SetWindowPlacement(windowHandle, ref placement);
            }
            catch (InvalidOperationException)
            {
                // Parsing placement XML failed. Fail silently.
            }
        }

        private static string GetPlacement(IntPtr windowHandle)
        {
            WINDOWPLACEMENT placement;
            GetWindowPlacement(windowHandle, out placement);

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8))
                {
                    Serializer.Serialize(xmlTextWriter, placement);
                    byte[] xmlBytes = memoryStream.ToArray();
                    return Encoding.GetString(xmlBytes);
                }
            }
        }
        public static void ApplyPlacement(this Window window)
        {
            var className = window.GetType().Name;
            try
            {
                var pos = File.ReadAllText(Directory + "\\" + className + ".pos");
                SetPlacement(new WindowInteropHelper(window).Handle, pos);
            }
            catch (Exception exception)
            {
                Log.Error("Couldn't read position for " + className, exception);
            }

        }

        public static void SavePlacement(this Window window)
        {
            var className = window.GetType().Name;
            var pos =  GetPlacement(new WindowInteropHelper(window).Handle);
            try
            {
                File.WriteAllText(Directory + "\\" + className + ".pos", pos);
            }
            catch (Exception exception)
            {
                Log.Error("Couldn't write position for " + className, exception);
            }
        }
        private static string Directory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

    }
}

在你的代码后台中,添加以下两个方法:
///This method is save the actual position of the window to file "WindowName.pos"
private void ClosingTrigger(object sender, EventArgs e)
{
    this.SavePlacement();
}
///This method is load the actual position of the window from the file
protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    this.ApplyPlacement();
}

在XAML窗口中,您需要添加以下内容:
Closing="ClosingTrigger"

3
默认解决此问题的方法是使用设置文件。设置文件的问题在于您必须定义所有设置并编写代码以自行复制数据。如果要跟踪许多属性,则相当繁琐。
我为此制作了一个非常灵活且易于使用的库,您只需告诉它要跟踪哪个对象的哪些属性,它就会完成其余工作。如果您喜欢,还可以对其进行详细配置。
该库名为Jot (github),这是我写的一篇旧的CodeProject文章
以下是如何使用它来跟踪窗口的大小和位置:
public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}
Jot vs. 设置文件:使用Jot可以少写很多代码,而且出错率更低,因为你只需要提及每个属性一次。使用设置文件时,你需要在明确创建属性时提及每个属性5次:在代码中额外提及四次以复制值。
存储、序列化等完全可配置。此外,当使用IOC时,甚至可以将其连接起来,使其自动应用于解析的所有对象,这样你所需做的就是在其上打上[Trackable]属性,从而使属性持久化。
我写这些是因为我认为这个库非常棒,我想大声表扬它。

很好,谢谢你 - 我已经在一个新类中使用了你的代码片段来设置状态跟踪器,并根据程序名称设置路径。从现在开始,我只需要写一行代码,所有窗口属性都会被处理。 - CptObvious
一定要查看 Github 页面。此解决方案支持多个监视器:https://github.com/anakic/Jot#real-world-formwindow-tracking - Matt Varblow

1

我写了一个快速类来实现这个功能。这里是它的调用方法:

    public MainWindow()
    {
        FormSizeSaver.RegisterForm(this, () => Settings.Default.MainWindowSettings,
                                   s =>
                                   {
                                       Settings.Default.MainWindowSettings = s;
                                       Settings.Default.Save();
                                   });
        InitializeComponent();
        ...

这里是代码:

public class FormSizeSaver
{
    private readonly Window window;
    private readonly Func<FormSizeSaverSettings> getSetting;
    private readonly Action<FormSizeSaverSettings> saveSetting;
    private FormSizeSaver(Window window, Func<string> getSetting, Action<string> saveSetting)
    {
        this.window = window;
        this.getSetting = () => FormSizeSaverSettings.FromString(getSetting());
        this.saveSetting = s => saveSetting(s.ToString());

        window.Initialized += InitializedHandler;
        window.StateChanged += StateChangedHandler;
        window.SizeChanged += SizeChangedHandler;
        window.LocationChanged += LocationChangedHandler;
    }

    public static FormSizeSaver RegisterForm(Window window, Func<string> getSetting, Action<string> saveSetting)
    {
        return new FormSizeSaver(window, getSetting, saveSetting);
    }


    private void SizeChangedHandler(object sender, SizeChangedEventArgs e)
    {
        var s = getSetting();
        s.Height = e.NewSize.Height;
        s.Width = e.NewSize.Width;
        saveSetting(s);
    }

    private void StateChangedHandler(object sender, EventArgs e)
    {
        var s = getSetting();
        if (window.WindowState == WindowState.Maximized)
        {
            if (!s.Maximized)
            {
                s.Maximized = true;
                saveSetting(s);
            }
        }
        else if (window.WindowState == WindowState.Normal)
        {
            if (s.Maximized)
            {
                s.Maximized = false;
                saveSetting(s);
            }
        }
    }

    private void InitializedHandler(object sender, EventArgs e)
    {
        var s = getSetting();
        window.WindowState = s.Maximized ? WindowState.Maximized : WindowState.Normal;

        if (s.Height != 0 && s.Width != 0)
        {
            window.Height = s.Height;
            window.Width = s.Width;
            window.WindowStartupLocation = WindowStartupLocation.Manual;
            window.Left = s.XLoc;
            window.Top = s.YLoc;
        }
    }

    private void LocationChangedHandler(object sender, EventArgs e)
    {
        var s = getSetting();
        s.XLoc = window.Left;
        s.YLoc = window.Top;
        saveSetting(s);
    }
}

[Serializable]
internal class FormSizeSaverSettings
{
    public double Height, Width, YLoc, XLoc;
    public bool Maximized;

    public override string ToString()
    {
        using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, this);
            ms.Position = 0;
            byte[] buffer = new byte[(int)ms.Length];
            ms.Read(buffer, 0, buffer.Length);
            return Convert.ToBase64String(buffer);
        }
    }

    internal static FormSizeSaverSettings FromString(string value)
    {
        try
        {
            using (var ms = new MemoryStream(Convert.FromBase64String(value)))
            {
                var bf = new BinaryFormatter();
                return (FormSizeSaverSettings) bf.Deserialize(ms);
            }
        }
        catch (Exception)
        {
            return new FormSizeSaverSettings();
        }
    }
}

window.Intitialized 应该改为 window.Loaded,请参见 http://mostlytech.blogspot.com/2008/01/maximizing-wpf-window-to-second-monitor.html - Gleb Sevruk
@Gleb,我认为两种方法都可以。你在Initialized上遇到问题了吗? - tster
是的,如果只使用初始化事件,最大化窗口将在错误的屏幕上。我所做的事情似乎有效:现在我也订阅了Loaded事件。 我将 _window.WindowState = s.Maximized ? WindowState.Maximized : WindowState.Normal; 代码行移动到“Loaded”事件处理程序中。 window.Initialized += InitializedHandler; window.Loaded += LoadedHandler;顺便说一句:我喜欢这种方法。 - Gleb Sevruk

1
在您的默认设置中创建一个名为WindowXml的字符串。
在窗口加载和关闭事件上使用此扩展方法来恢复和保存窗口大小和位置。
using YourProject.Properties;
using System;
using System.Linq;
using System.Windows;
using System.Xml.Linq;

namespace YourProject.Extensions
{
    public static class WindowExtensions
    {
        public static void SaveSizeAndLocation(this Window w)
        {
            try
            {
                var s = "<W>";
                s += GetNode("Top", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Top : w.Top);
                s += GetNode("Left", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Left : w.Left);
                s += GetNode("Height", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Height : w.Height);
                s += GetNode("Width", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Width : w.Width);
                s += GetNode("WindowState", w.WindowState);
                s += "</W>";

                Settings.Default.WindowXml = s;
                Settings.Default.Save();
            }
            catch (Exception)
            {
            }
        }

        public static void RestoreSizeAndLocation(this Window w)
        {
            try
            {
                var xd = XDocument.Parse(Settings.Default.WindowXml);
                w.WindowState = (WindowState)Enum.Parse(typeof(WindowState), xd.Descendants("WindowState").FirstOrDefault().Value);
                w.Top = Convert.ToDouble(xd.Descendants("Top").FirstOrDefault().Value);
                w.Left = Convert.ToDouble(xd.Descendants("Left").FirstOrDefault().Value);
                w.Height = Convert.ToDouble(xd.Descendants("Height").FirstOrDefault().Value);
                w.Width = Convert.ToDouble(xd.Descendants("Width").FirstOrDefault().Value);
            }
            catch (Exception)
            {
            }
        }

        private static string GetNode(string name, object value)
        {
            return string.Format("<{0}>{1}</{0}>", name, value);
        }
    }
}

到目前为止最好的方法-只需要在MainWindow()中调用RestoreSizeAndLocation(),并在InitializeComponent()之后调用,否则会出现明显的跳跃。 - Duncan Groenewald

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