If I use dragMove the wpf window will not move to a location where the y value is negative. I can however set the windows top value to a negative value. Is there a simple way to enable dragMove to allow the top of the window to be moved above the displays 0 position?
Edit:
It seems that this is the default window's handling of moveWindow. Verified with a call to SendMessage( hwnd, WM_SYSCOMMAND, SC_MOVE, null);
As I found, the window will move to "negative" location, but will then jump back. To prevent this you could do something like:
public partial class Window1: Window {
public Window1() {
InitializeComponent();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
DragMove();
}
public struct WINDOWPOS {
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public UInt32 flags;
};
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
switch(msg) {
case 0x46://WM_WINDOWPOSCHANGING
if(Mouse.LeftButton != MouseButtonState.Pressed) {
WINDOWPOS wp = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
wp.flags = wp.flags | 2; //SWP_NOMOVE
Marshal.StructureToPtr(wp, lParam, false);
}
break;
}
return IntPtr.Zero;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
}
Handling WM_WINDOWPOSCHANGING this way will prevent any movement of the window unless left mouse button is pressed. This includes maximizing the window and programmatic change of window position as well, so you'll have to adapt the code if you need another behavior.
Related
The reported issue occurs when the check box in below image(This PC -->Properties-->Advanced System Settings-->(under Performance in Advanced tab click Settings)) is disabled.
Try to get the mouse cursor position while dragging a window in WPF. The location of window is updated only when mouse is pressed and released, not when it window dragged.
public partial class MainWindow : Window
{
private const int WM_MOVING = 0x0216;
private HwndSource _hwndSrc;
private HwndSourceHook _hwndSrcHook;
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
this.Unloaded += MainWindow_Unloaded;
}
private void MainWindow_Unloaded(object sender, RoutedEventArgs e)
{
_hwndSrc.RemoveHook(_hwndSrcHook);
_hwndSrc.Dispose();
_hwndSrc = null;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_hwndSrc = HwndSource.FromDependencyObject(this) as HwndSource;
_hwndSrcHook = FilterMessage;
_hwndSrc.AddHook(_hwndSrcHook);
}
private IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_MOVING:
OnLocationChange();
break;
}
return IntPtr.Zero;
}
private void OnLocationChange()
{
Rect windowRect = new Rect(this.Left, this.Top, this.Width, this.Height);
}
}
Need the location of window to update when it is dragged by mouse.
I'm trying to anchor a WPF Window (NOT a control inside a window) to TopRight for example, by default Windows anchors all windows to top left.
I tried the following code
private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e)
{
double delta = e.PreviousSize.Width - e.NewSize.Width;
Left += delta;
}
It works, but the window stutters/flickers during rapid size changes (e.g Animations)
I tried googling it but did not find a good solution, am I missing something ?
I managed to solve the problem with the help of this post.
Here's the code
public partial class MainWindow : Window
{
private double right;
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
right = Left + Width;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == (int)WindowMessage.WindowPositionChanging)
{
var windowPosition = (WindowPosition)Marshal.PtrToStructure(lParam, typeof(WindowPosition));
bool isMove = !windowPosition.Flags.HasFlag(WindowPositionFlags.NoMove); //0x0002
bool isSize = !windowPosition.Flags.HasFlag(WindowPositionFlags.NoSize); //0x0001
if (isMove)
{
right = windowPosition.Left + windowPosition.Width;
}
else if (isSize)
{
windowPosition.Left = (int)(right - windowPosition.Width);
windowPosition.Top = (int)Top;
windowPosition.Flags = (WindowPositionFlags)((int)windowPosition.Flags & 0xfffd); //remove the NoMove flag
Marshal.StructureToPtr(windowPosition, lParam, true);
}
}
return IntPtr.Zero;
}
Hope it helps someone
I want to use in my wpf aplication notify icon (with .dll library in project http://www.codeproject.com/Articles/36468/WPF-NotifyIcon).
But I don't know, how to show my window (after minimize to tray) by double click in tray icon.
I declared new command
namespace MyBasicFlyffKeystroke
{
class ShowWindowCommand : ICommand
{
public void Execute(object parameter)
{
Window1 window = new Window1();
window.Show();
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
}
And I used it in my window1.xaml file:
<tb:TaskbarIcon x:Name="notifyIcon" IconSource="icon.ico" ToolTipText="MyBasicFlyffKeystroke"
DoubleClickCommand="{StaticResource ShowWindow}">
</tb:TaskbarIcon>
and
<Grid.Resources>
<my:ShowWindowCommand x:Key="ShowWindow" />
</Grid.Resources>
But after double clicking open new instance with Window1... Is any metod here?
Best regards,
Dagna
Try add an event handler for window messages
Command
namespace MyBasicFlyffKeystroke
{
class ShowWindowCommand : ICommand
{
public void Execute(object parameter)
{
// Broadcast isn't a good idea but work...
NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero);
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
}
In Window1
protected override void OnSourceInitialized(EventArgs e) {
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
if (msg == NativeMethods.WM_SHOWME) {
WindowState = WindowState.Normal;
}
return IntPtr.Zero;
}
And in NativeMethods (UPDATED)
public static readonly int HWND_BROADCAST = 0xffff;
public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
[DllImport("user32.dll")]
public static extern int RegisterWindowMessage(string message);
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
Application.Current.Window1.Show();
this worked for me
Following MS guidelines, my WPF application's App constructor includes the following code for proper focus behavior:
HwndSource.DefaultAcquireHwndFocusInMenuMode = false;
Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
As explained in this article, these settings prevent focus stealing.
However, setting DefaultRestoreFocusMode to None has a bad side effect. When using Alt+Tab to leave a WPF application and then return to it, the WPF application doesn't get focus. However, if I don't set DefaultRestoreFocusMode to none, it does get focus as expected. Is there a way to prevent focus stealing but have focus still set when returning to a WPF application via Alt+Tab?
-Craig
I prevent my wpf window from getting focus by doing the below and i can still activate it by using ALT-TAB or clicking on it's taskbar item.
Here you change the window styles on your window so that it has no activate.
var yourWindow = new YourWindowType();
//set the windowstyle to noactivate so the window doesn't get focus
yourWindow.SourceInitialized += (s, e) =>
{
var interopHelper = new WindowInteropHelper(yourWindow);
int exStyle = User32.GetWindowLong(interopHelper.Handle, (int)WindowLongFlags.GWL_EXSTYLE);
User32.SetWindowLong(interopHelper.Handle, (int)WindowLongFlags.GWL_EXSTYLE, exStyle | (int)WindowStylesEx.WS_EX_NOACTIVATE);
//If you have trouble typing into your form's textboxes then do this
ElementHost.EnableModelessKeyboardInterop(yourWindow);
};
This is something i added as an extra precaution, plus it lets you drag your window around if it is borderless:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
//don't activate the window when you click on it.
case WindowMessage.WM_MOUSEACTIVATE:
handled = true;
return (IntPtr)MouseActivate.MA_NOACTIVATE;
//For Borderless Windows: occurs while dragging. it reports new position before it has been finalized.
//otherwise you wont see the window moving while you're dragging it
case WindowMessage.WM_MOVING:
RECT rect = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
User32.SetWindowPos(new WindowInteropHelper(this).Handle, Hwnd.HWND_TOPMOST,
rect.Left, rect.Top, rect.Width, rect.Height,
SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOSIZE);
break;
}
return IntPtr.Zero;
}
These add a hook so that WndProc is actually called in WPF:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
if (source == null) return;
source.AddHook(WndProc);
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
if (source == null) return;
source.RemoveHook(WndProc);
}
Just an FYI.. this still works even though you don't get focus:
private void WpfPillForm_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Here's the Win32 API declarations so you don't have to look them up:
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}
public static class MouseActivate
{
public const int MA_ACTIVATE = 1;
public const int MA_ACTIVATEANDEAT = 2;
public const int MA_NOACTIVATE = 3;
public const int MA_NOACTIVATEANDEAT = 4;
}
public enum WindowLongFlags : int
{
GWL_EXSTYLE = -20,
GWLP_HINSTANCE = -6,
GWLP_HWNDPARENT = -8,
GWL_ID = -12,
GWL_STYLE = -16,
GWL_USERDATA = -21,
GWL_WNDPROC = -4,
DWLP_USER = 0x8,
DWLP_MSGRESULT = 0x0,
DWLP_DLGPROC = 0x4
}
public const int WM_MOVING = 0x0216;
public const uint WS_EX_NOACTIVATE = 0x08000000,
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowLong(IntPtr hwnd, int index);
I'm using WPF's OpenFileDialog, and I'm looking for a way to make sure it is centered in the parent window when shown. It seems to be missing obvious properties like StartupPosition that might enable this.
Does anybody know the secret?
Update: It seems that the first time I open it, it does appear in the center of the parent, but if I move it, it then remembers its position, and doesn't open centered on subsequent occassions.
here is the code of a generic class that allows to play with "sub dialogs" like this one:
public class SubDialogManager : IDisposable
{
public SubDialogManager(Window window, Action<IntPtr> enterIdleAction)
:this(new WindowInteropHelper(window).Handle, enterIdleAction)
{
}
public SubDialogManager(IntPtr hwnd, Action<IntPtr> enterIdleAction)
{
if (enterIdleAction == null)
throw new ArgumentNullException("enterIdleAction");
EnterIdleAction = enterIdleAction;
Source = HwndSource.FromHwnd(hwnd);
Source.AddHook(WindowMessageHandler);
}
protected HwndSource Source { get; private set; }
protected Action<IntPtr> EnterIdleAction { get; private set; }
void IDisposable.Dispose()
{
if (Source != null)
{
Source.RemoveHook(WindowMessageHandler);
Source = null;
}
}
private const int WM_ENTERIDLE = 0x0121;
protected virtual IntPtr WindowMessageHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_ENTERIDLE)
{
EnterIdleAction(lParam);
}
return IntPtr.Zero;
}
}
And this is how you would use it in a standard WPF app. Here I just copy the parent window size, but I'll let you do the center math :-)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
bool computed = false; // do this only once
int x = (int)Left;
int y = (int)Top;
int w = (int)Width;
int h = (int)Height;
using (SubDialogManager center = new SubDialogManager(this, ptr => { if (!computed) { SetWindowPos(ptr, IntPtr.Zero, x, y, w, h, 0); computed= true; } }))
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog(this);
}
}
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
}
CommonDialog in WPF does not inherit from window class, so it does not have StartupPosition property.
Check this blog post for one solution: OpenFileDialog in .NET on Vista
In short, it wraps dialog in a window and then shows it.