【问题标题】:Window StateChanging event in WPFWPF 中的窗口 StateChanging 事件
【发布时间】:2010-10-29 22:21:14
【问题描述】:

我需要在 WPF 应用程序最小化之前处理它,而不是当它已经存在时。 我在 Window 对象上找到了 StateChanged,但是当 Window 对象已经处于最小化状态时它会触发,那就太晚了。

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

是否可以创建这样的事件?

【问题讨论】:

标签: .net wpf user-interface xaml


【解决方案1】:

在使用 Spy++ 最小化之前找到在窗口上调用的 windows 消息。第一个被调用的是 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#

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;           
    }       

}
}

【讨论】:

    【解决方案2】:

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

    窗口的最小化调用可以从许多地方发生,而不仅仅是 Window Chrome 上的最小化按钮(例如,右键单击任务栏,或从 Windows 任务管理器)和 AFAIK,没有办法直接处理从 Window Chrome 触发的按钮事件(如果有人知道如何执行此操作,请告诉我!)。

    好消息是你可以伪造它,但这不是微不足道的,所以你必须决定它是否值得。首先,您必须将标准的 Window Chrome 替换为您自己的。您可以了解如何做到这一点here

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

    请记住,您仍然无法通过任务栏/Windows 任务管理器检测或阻止用户最小化,因此它可能不是您想要的。

    【讨论】:

    • 感谢您的回复。我已经在窗口上有自定义镶边,并且我已经从按钮最小化的系统菜单中捕获 Windows 消息:在标题栏中,任务栏上的系统菜单,Alt+Space 上的系统菜单。但是我仍然无法在 Toggle Desktop (Win+D) 和 Minimize All (Win+M) 的应用程序中捕获事件...
    猜你喜欢
    • 1970-01-01
    • 2016-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多