Show window after double click in notify icon (after minimize to tray) - wpf

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

Related

When "Show window content while dragging " is disabled, dragged window location value does not update in WPF

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.

WPF - show window in Action

I have a small problem. I have method which register global hotkey, when I press hotkey, program call Action. In Action method I would like Show window, but don't work it.
This is my code:
MainWindow.cs:
_hotKeyRegistrator.Add(Modifier.Ctrl, Keys.A, () => {Show();}
HotkeyRegistrator.cs:
public class HotkeyRegistrator
{
private HwndSource _source;
private readonly WindowInteropHelper _windowInteropHelper;
private const int HotkeyId = 9000;
private const int WmHotkey = 0x0312;
private List<HotKey> _hotKeys;
public HotkeyRegistrator(Window window)
{
_windowInteropHelper = new WindowInteropHelper(window);
_source = HwndSource.FromHwnd(_windowInteropHelper.Handle);
_source?.AddHook(HwndHook);
_hotKeys = new List<HotKey>();
}
[DllImport("User32.dll")]
private static extern bool RegisterHotKey([In] IntPtr hWnd, [In] int id, [In] uint fsModifiers, [In] uint vk);
[DllImport("User32.dll")]
private static extern bool UnregisterHotKey([In] IntPtr hWnd, [In] int id);
public void Add(Modifiers modifier, Keys key, Action action)
=> _hotKeys.Add(new HotKey(HotkeyId + _hotKeys.Count, modifier, key, action));
public void Register()
{
foreach (var hotKey in _hotKeys)
{
if (!RegisterHotKey(_windowInteropHelper.Handle, hotKey.Id, hotKey.Modifier, hotKey.Key))
{
throw new Exception("Cannot register hotkey");
}
}
}
public void UnRegisterAll()
{
_source.RemoveHook(HwndHook);
_source = null;
foreach (var hotKey in _hotKeys)
{
UnregisterHotKey(_windowInteropHelper.Handle, hotKey.Id);
}
_hotKeys = null;
}
private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WmHotkey)
_hotKeys.FirstOrDefault(x => x.Id == wParam.ToInt32())?.Action.Invoke();
return IntPtr.Zero;
}
}
Hotkey.cs:
public class HotKey
{
public int Id { get; set; }
public uint Modifier { get; }
public uint Key { get; }
public Action Action { get; }
public HotKey(int id, Modifiers modifier, Keys key, Action action)
{
Id = id;
Modifier = (uint)modifier;
Key = (uint)key;
Action = action;
}
}
Action method is called using Invoke method. When I press CTRL + A, call action and Show method, but window dont open.
Thanks for advices.
Problem solved. My window has set WindowState="Minimized" attribute on startup. When I would like call Show() after press global shortcut, code must be this:
_hotKeyRegistrator.Add(Modifier.Ctrl, Keys.A, () => {
WindowState = WindowState.Normal;
Show();
});

WPF Listview does not scroll (with mouse wheel) when Application not in focus

I have a WPF app (written in C#) which has a Listview control which scrolls perfectly with the mouse wheel when the app is in focus.
However when the app is not in focus, even when the mouse pointer is over the app & list view area, the Listview does not scroll. I continue to see mousehover related effects on the app but no mousewheel event is received. This is inline with how most of the other apps work on my desktop however some of them (like Facebook messenger) support scrolling without focus which i would like to mimic in my WPF app.
I have searched MSDN forums and Stackoverflow and seen multiple solutions for Windows Forms however they were questions asked over 5 years ago and i was wondering if someone has managed to do it relatively easily on .net 4.5 and can point me to possible solutions.
---Edit---
I was able to progress to some extent on this thanks to this thread C# ListView mouse wheel scroll without focus
Here is how my the function that receives the mousewheel looks
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
Console.WriteLine((short)((hookStruct.mouseData)>>16));
MouseWheelEventArgs myArgs = new MouseWheelEventArgs(System.Windows.Input.Mouse.PrimaryDevice, (int)hookStruct.time, (short)((hookStruct.mouseData)>>16));
myMainFrame.SidePanelControl.ScrollTheListView(myArgs);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
As you can see i am initializing a MouseWheelEventArgs instance and have the time, delta and the mouse device attributes.
How do i go about passing this mousewheel event to my listview scrollviewer?
Managed to get this working. Here is my class.
All one needs to do to use the class is
Initialize InterceptMouse passing it the app/listview/etc pointer
Start intercepting the mouse when the app is not in focus but the corresponding mouseenter event has occured.
As long as the event is mousewheel the scrollviewer of the listview will be sent the mouseWheel event.
Stop intercepting the mouse when the app gets activated or mouseleave is called.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Forms;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using System.Diagnostics;
using System.Windows.Forms.Integration;
namespace myApp.HelperClasses
{
public class InterceptMouse
{
public static System.Windows.Controls.ListView myListview;
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public InterceptMouse(System.Windows.Controls.ListView myListviewParam)
{
myListview = myListviewParam;
}
public static void StartIntercepting()
{
_hookID = SetHook(_proc);
}
public static void StopIntercepting()
{
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
//Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y + "," + hookStruct.mouseData);
var delta = (short)((hookStruct.mouseData) >> 16);
var mouse = InputManager.Current.PrimaryMouseDevice;
var args = new MouseWheelEventArgs(mouse, Environment.TickCount, delta);
args.RoutedEvent = WindowsFormsHost.MouseWheelEvent;
Decorator border = VisualTreeHelper.GetChild(myListview, 0) as Decorator;
// Get scrollviewer
ScrollViewer scrollViewer = border.Child as ScrollViewer;
scrollViewer.RaiseEvent(args);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}

How do I center the OpenFileDialog to its parent Window in WPF?

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.

How do I move a wpf window into a negative top value?

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.

Resources