【问题标题】:Restoring real window size in WPF在 WPF 中恢复实际窗口大小
【发布时间】:2019-12-16 12:14:09
【问题描述】:

我正在尝试在我的 WPF 应用程序中实现存储和恢复主窗口状态和大小。我当前的代码如下所示:

  • MainWindowViewModel.cs(在主窗口的OnLoaded 上运行):

    public void NotifyLoaded()
    {
        var uiConfig = configurationService.Configuration.UI;
    
        if (uiConfig.MainWindowSizeSet.Value)
            access.SetWindowSize(new System.Windows.Size(uiConfig.MainWindowWidth.Value, 
                uiConfig.MainWindowHeight.Value));
    
        if (uiConfig.MainWindowLocationSet.Value)
            access.SetWindowLocation(new System.Windows.Point(uiConfig.MainWindowX.Value,
                uiConfig.MainWindowY.Value));
    
        if (uiConfig.MainWindowMaximized.Value)
            access.SetWindowMaximized(true);
    }
    
  • access 是一个IMainWindowAccess,由MainWindow 本身实现(这是我在视图模型和窗口之间提供通信的方式,同时仍然保持逻辑和视图分离)。方法的实现方式如下:

    void IMainWindowAccess.SetWindowSize(Size size)
    {
        this.Width = size.Width;
        this.Height = size.Height;
    }
    
    void IMainWindowAccess.SetWindowLocation(Point point)
    {
        this.Left = point.X;
        this.Top = point.Y;
    }
    
    void IMainWindowAccess.SetWindowMaximized(bool maximized)
    {
        this.WindowState = maximized ? WindowState.Maximized : WindowState.Normal;
    }
    
  • 我在关闭窗口时存储窗口位置和大小,但前提是窗口未最大化。我这样做是为了避免用户尝试恢复窗口并将其恢复到最大化大小时的情况。

    public void NotifyClosingWindow()
    {
        var windowSize = access.GetWindowSize();
        var windowLocation = access.GetWindowLocation();
    
        var maximized = access.GetMaximized();
        configurationService.Configuration.UI.MainWindowMaximized.Value = maximized;
    
        if (!maximized)
        {
            Models.Configuration.UI.UIConfig uiConfig = configurationService.Configuration.UI;
    
            uiConfig.MainWindowWidth.Value = windowSize.Width;
            uiConfig.MainWindowHeight.Value = windowSize.Height;
            uiConfig.MainWindowSizeSet.Value = true;
    
            uiConfig.MainWindowX.Value = windowLocation.X;
            uiConfig.MainWindowY.Value = windowLocation.Y;
            uiConfig.MainWindowLocationSet.Value = true;
        }
    
        configurationService.Save();
    }
    

问题在于,虽然我在最大化窗口之前恢复了窗口的大小和位置(因此它应该恢复到以前的大小),但它仍然恢复到最大化的大小(有效地单击恢复按钮会改变最大化按钮 - 大小和位置保持不变)。

我应该如何设置窗口的大小和位置,然后最大化它,以便正确存储大小和位置?

【问题讨论】:

  • 您是否尝试过管理Window.StateChanged 事件?

标签: c# .net wpf window maximize


【解决方案1】:

你可以这样做

// 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)
    {
        Left = left;
        Top = top;
        Right = right;
        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)
    {
        X = x;
        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 WindowRestorerService
{
    private const int SW_SHOWNORMAL = 1;
    private const int SW_SHOWMINIMIZED = 2;

    private static Encoding encoding = new UTF8Encoding();
    private static 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);

    public static void SetPlacement(this Window window, string placementXml)
    {
        WindowRestorerService.SetPlacement(new WindowInteropHelper(window).Handle, placementXml);
    }

    /// <summary>
    /// Set the window to the relevent position using the placement information. 
    /// </summary>
    /// <param name="windowHandle">The window handle of the target information.</param>
    /// <param name="placementXml">The placement XML.</param>
    public static void SetPlacement(IntPtr windowHandle, string placementXml)
    {
        if (string.IsNullOrEmpty(placementXml))
            return;

        WINDOWPLACEMENT placement;
        byte[] xmlBytes = encoding.GetBytes(placementXml);

        try
        {
            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.
        }
    }

    public static string GetPlacement(this Window window)
    {
        return WindowRestorerService.GetPlacement(new WindowInteropHelper(window).Handle);
    }

    /// <summary>
    /// Retruns the serialize XML of the placement information for the 
    /// target window.
    /// </summary>
    /// <param name="windowHandle">The handle of the target window.</param>
    public static string GetPlacement(IntPtr windowHandle)
    {
        WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
        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 void OnClosing()
{
    MainWindowSettingsProvider settingsProvider = MainWindowSettingsProvider.Instance;
    settingsProvider.MainWindowSettings.WindowPlacementInfo = ((Window)View).GetPlacement();
    settingsProvider.Save();
}

并通过设置

[Export(typeof(IMainWindowView))]
public partial class MainWindowView : MetroWindow, IMainWindowView
{
    public MainWindowView()
    {
        InitializeComponent();
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        MainWindowSettingsProvider settingsProvider = MainWindowSettingsProvider.Instance;
        this.SetPlacement(settingsProvider.MainWindowSettings.WindowPlacementInfo);
    }
}

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多