.net WPF 中的 Window StateChanging 事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/926758/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Window StateChanging event in WPF
提问by Andrija
I need to handle WPF application right before it goes Minimize, not when it's already there. I found on Window object StateChanged, but it fires when Window object is already in Minimize state, then it's too late.
我需要在 WPF 应用程序最小化之前处理它,而不是在它已经存在时。我在 Window 对象 StateChanged 上找到了,但是当 Window 对象已经处于最小化状态时它会触发,那么为时已晚。
So, I need something like "StateChanging" event to handle, while Window object is still in previous state.
所以,我需要像“StateChanging”这样的事件来处理,而 Window 对象仍处于以前的状态。
Is it possible to create such event ?
是否有可能创建这样的事件?
回答by Andrija
Found windows messages called on window right before minimize using Spy++. First one that is called is WM_WINDOWPOSCHANGING. I didn't know windows is moving window on -32000, -32000 location point when minimizing widow, and those were the params in WM_WINDOWPOSCHANGING. Though, I have tested is only on Vista. http://blogs.msdn.com/oldnewthing/archive/2004/10/28/249044.aspx
在使用 Spy++ 最小化之前找到在窗口上调用的 Windows 消息。第一个被调用的是 WM_WINDOWPOSCHANGING。我不知道 Windows 在最小化寡妇时正在 -32000、-32000 位置点移动窗口,这些是 WM_WINDOWPOSCHANGING 中的参数。不过,我只在 Vista 上测试过。http://blogs.msdn.com/oldnewthing/archive/2004/10/28/249044.aspx
code used here was posted by Nir here
这里使用的代码由 Nir 发布在这里
here is sample code
这是示例代码
xaml:
xml:
<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#
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;
}
}
}
回答by micahtan
I don't think you'll be able to do it directly.
我认为你不能直接做到这一点。
A Minimize call to the window can happen from a number of places, not just the minimize button on the Window Chrome (e.g. The right clicking on the TaskBar, or from Windows Task Manager), and AFAIK, there's no way to directly handle button events fired from the Window Chrome (if somebody does know how to do this, please let me know!).
对窗口的最小化调用可以从很多地方发生,不仅仅是窗口 Chrome 上的最小化按钮(例如右键单击任务栏,或从 Windows 任务管理器),而且 AFAIK,没有办法直接处理按钮事件从 Window Chrome 发射(如果有人知道如何做到这一点,请告诉我!)。
The good newsis that you can fake it, but it's not trivial, so you'll have to decide if it's worth it. First, you'll have to replace the standard Window Chrome with your own. You can find out how to do that here.
的好消息是,你可以伪造它,但它不是小事,所以你必须决定它是否值得。首先,您必须将标准的 Window Chrome 替换为您自己的。您可以在此处了解如何执行此操作。
Secondly, you'll have to create your own "Maximize/Minimize/Close" Buttons and wire up the events to the appropriate behaviors. Since this is your own UI, you are free to listen to and cancel the Button events as you choose.
其次,您必须创建自己的“最大化/最小化/关闭”按钮并将事件连接到适当的行为。由于这是您自己的 UI,因此您可以随意收听和取消 Button 事件。
Keep in mind that you still won't be able to detect or prevent users from Minimizing via the TaskBar/Windows Task Manager, so it may not be exactly what you're looking for.
请记住,您仍然无法通过任务栏/Windows 任务管理器检测或阻止用户最小化,因此它可能不是您正在寻找的。

