WPF中的窗口状态改变事件

14

我需要在WPF应用程序最小化之前处理它,而不是当它已经最小化时再处理。

我发现了Window对象的StateChanged事件,但它在Window对象已经处于最小化状态时触发,那就太晚了。

所以,我需要像“StateChanging”这样的事件来处理,同时Window对象仍处于先前的状态。

是否有可能创建这样的事件?


2个回答

18
在最小化窗口之前,使用Spy++发现了称为“窗口位置正在更改”的窗口消息。第一个被调用的是WM_WINDOWPOSCHANGING。我不知道当最小化窗口时Windows会将窗口移动到-32000、-32000的位置点,并且这些参数在WM_WINDOWPOSCHANGING中。但是,我只在Vista上进行了测试。 http://blogs.msdn.com/oldnewthing/archive/2004/10/28/249044.aspx 此处使用的代码由Nir发布here 以下是示例代码
xaml:
<Window x:Class="WindowStateTest2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>

        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
        <Button Click="btnClear_Click" Grid.Row="0" x:Name="btnClear">Clear</Button>            

        <TextBox Name="txt" VerticalScrollBarVisibility="Visible" Grid.Row="2"></TextBox>
</Grid>
</Window>

C#(读作"C sharp")
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace WindowStateTest2
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        this.StateChanged += new EventHandler(Window1_StateChanged);
        this.SourceInitialized += new EventHandler(Window1_SourceInitialized);

    }

    #region Event handlers

    void btnClear_Click(object sender, RoutedEventArgs e)
    {
        this.txt.Text = string.Empty;
    }
    void Window1_SourceInitialized(object sender, EventArgs e)
    {
        AttachWndProc();
    }

    void Window1_StateChanged(object sender, EventArgs e)
    {
        if (this.WindowState == WindowState.Minimized)
            Console.WriteLine("SC: " + this.WindowState);
    } 

    #endregion

    #region Const

    private int SYSCOMMAND = 0x0112;
    private int SC_MINIMIZE = 0xf020;
    private int WINDOWPOSCHANGING = 0x0046;

    #endregion

    private void AttachWndProc()
    {
        HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
        source.AddHook(new HwndSourceHook(WndProc));
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct WINDOWPOSPARAMS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public int flags;
    }


    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WINDOWPOSCHANGING)               
        {
            WINDOWPOSPARAMS param = (WINDOWPOSPARAMS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOSPARAMS));
            if (param.x == -32000 && param.y == -32000)
            {
                Output("");

                                    // EVENT WOULD BE RAISED HERE

                Output("State before minimize:");
                Output(string.Format("CurrentState: {0}", this.WindowState));
                Output(string.Format("Location {0} {1}: ", this.Top, this.Left));
                Output("");
            }
        }

        // process minimize button
        if (msg == SYSCOMMAND && SC_MINIMIZE == wParam.ToInt32())
        {
            Output("Minimize clicked");             
        }

        handled = false;
        return IntPtr.Zero;
    }

    public void Output(object output)
    {
        this.txt.Text += output.ToString();
        this.txt.Text += Environment.NewLine;           
    }       

}
}

0

我认为你不会直接做到这一点。

窗口的最小化调用可能来自许多地方,而不仅仅是窗口Chrome上的最小化按钮(例如,在任务栏上右键单击或从Windows任务管理器中),据我所知,没有直接处理从窗口Chrome触发的按钮事件的方法(如果有人知道如何做到这一点,请告诉我!)。

好消息是你可以伪造它,但这并不容易,所以你必须决定它是否值得。首先,你必须用自己的Chrome替换标准的窗口Chrome。你可以在这里找到如何做到这一点。

其次,你必须创建自己的“最大化/最小化/关闭”按钮,并将事件连接到适当的行为。由于这是你自己的UI,你可以自由地监听和取消按钮事件。

请记住,您仍然无法检测或防止用户通过任务栏/Windows任务管理器最小化窗口,因此这可能并不完全符合您的要求。

1
谢谢您的回复。我已经在窗口上有自定义的Chrome,并且我已经从系统菜单中捕获了窗口消息,包括标题栏、任务栏和Alt+Space的系统菜单。但是我仍然无法在应用程序中捕获Toggle Desktop(Win+D)和Minimize All(Win+M)事件... - Andrija

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