我已经创建了一个控制台应用程序来监视剪贴板何时更改。它工作正常,下面的控制台代码部分显示了代码。
我现在的问题是,如何使用MVVM为WPF应用程序实现这一点。我想我需要将主窗口传递给我的视图模型,这是MVVM的正确方式吗?
使现代化
这是我创建窗口的尝试。我已经读到我需要实现HwndHost,这是我在我的类MyFirstWindow中完成的。不过我不知道怎么把窗户藏起来?
我假设在ClipboardManager下面的另一个类中,我需要创建MyFirstWindow的一个实例。然而,我不确定要通过什么样的HandleRef?
class MyFirstWindow : HwndHost
{
IntPtr hwndHost;
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
hwndHost = IntPtr.Zero;
hwndHost = CreateWindowEx(0, "static", "", WS_CHILD,
0, 0, 50, 50, hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero, 0);
return new HandleRef(this, hwndHost);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}
internal const int
WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000,
LBS_NOTIFY = 0x00000001,
HOST_ID = 0x00000002,
LISTBOX_ID = 0x00000001,
WS_VSCROLL = 0x00200000,
WS_BORDER = 0x00800000;
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
}
我已经在我的WPF应用程序中创建了下面的ClipboardManager类。
class ClipboardManager : IDisposable
{
#region variable declaration
/// <summary>
/// Next clipboard viewer window
/// </summary>
private IntPtr _hWndNextViewer;
/// <summary>
/// The <see cref="HwndSource"/> for this window.
/// </summary>
private HwndSource _hWndSource;
private string _clipboardContent;
#endregion
#region property declaration
public string ClipboardContent
{
get
{
return _clipboardContent;
}
set
{
_clipboardContent = value;
}
}
#endregion
public ClipboardManager()
{
hwnd = new MyFirstWindow();
InitCBViewer();
}
private void InitCBViewer(System.Windows.Window wnd)
{
WindowInteropHelper wih = new WindowInteropHelper(wnd);
_hWndSource = HwndSource.FromHwnd(wih.Handle);
_hWndSource.AddHook(WinProc); // start processing window messages
_hWndNextViewer = Win32.SetClipboardViewer(_hWndSource.Handle); // set this window as a viewer
}
private void CloseCBViewer()
{
// remove this window from the clipboard viewer chain
Win32.ChangeClipboardChain(_hWndSource.Handle, _hWndNextViewer);
_hWndNextViewer = IntPtr.Zero;
_hWndSource.RemoveHook(this.WinProc);
}
private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
if (wParam == _hWndNextViewer)
{
// clipboard viewer chain changed, need to fix it.
_hWndNextViewer = lParam;
}
else if (_hWndNextViewer != IntPtr.Zero)
{
// pass the message to the next viewer.
Win32.SendMessage(_hWndNextViewer, msg, wParam, lParam);
}
break;
case Win32.WM_DRAWCLIPBOARD:
// clipboard content changed
if (Clipboard.ContainsText())
{
ClipboardContent = Clipboard.GetText();
}
// pass the message to the next viewer.
Win32.SendMessage(_hWndNextViewer, msg, wParam, lParam);
break;
}
return IntPtr.Zero;
}
public void Dispose()
{
CloseCBViewer();
}
}
赢得32级
internal static class Win32
{
/// <summary>
/// The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
/// the content of the clipboard has changed.
/// </summary>
internal const int WM_DRAWCLIPBOARD = 0x0308;
/// <summary>
/// A clipboard viewer window receives the WM_CHANGECBCHAIN message when
/// another window is removing itself from the clipboard viewer chain.
/// </summary>
internal const int WM_CHANGECBCHAIN = 0x030D;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
}