tags:

views:

1221

answers:

2

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.

So, I need something like "StateChanging" event to handle, while Window object is still in previous state.

Is it possible to create such event ?

A: 

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!).

The good news is 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.

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.

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.

micahtan
Thank you for reply. I already have custom chrome on window, and I have catching windows messages from system menu on button minimize: in title bar, system menu on task bar, system menu on Alt+Space. But I still can't capture event in application for Toggle Desktop (Win+D) and Minimize All (Win+M)...
Andrija
+1  A: 

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

code used here was posted by Nir here

here is sample code

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

}
}
Andrija