我正在使用Calibun Micro框架编写一个WPF应用程序。它实现了一个自动注销系统,该系统将在预定义的一段时间不活动后自动将用户签出应用程序。我使用这里找到的方法检查不活动。
我在我的应用程序中创建对话框(使用windowmanager.showdialog(viewmodel)),它需要各种用户输入,并且我需要在这些对话框上实现自动注销功能。我遇到的问题是,我似乎无法从对话框窗口获得Hwnd详细信息。我目前正在我的视图模型中执行以下操作:
public class BaseViewModel : Screen
{
public BaseViewModel(User currentUser, IEventAggregator eventAggregator)
{
BaseEventAggregator = eventAggregator;
CurrentUser = currentUser;
InitializeTimer();
}
private void InitializeTimer()
{
var currentView = GetView();
if (currentView as Window != null)
{
var windowSpecificOsMessageListener = HwndSource.FromHwnd(new WindowInteropHelper(currentView as Window).Handle);
if (windowSpecificOsMessageListener != null)
{
windowSpecificOsMessageListener.AddHook(new HwndSourceHook(CallBackMethod));
}
_autoTimer = new Timer
{
Interval = Constants.Seconds * 1000
};
_autoTimer.Tick += delegate(object sender, EventArgs args)
{
_autoTimer.Stop();
_autoTimer.Enabled = false;
_autoTimer = null;
BaseEventAggregator.Publish(new SignOutEventMessage());
};
_autoTimer.Enabled = true;
}
}
private IntPtr CallBackMethod(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
// Listening OS message to test whether it is a user activity
if ((msg >= 0x0200 && msg <= 0x020A) || (msg <= 0x0106 && msg >= 0x00A0) || msg == 0x0021)
{
ResetAutoTimer();
}
else
{
// For debugging purpose
// If this auto logoff does not work for some user activity, you can detect the integer code of that activity using the following line.
//Then All you need to do is adding this integer code to the above if condition.
System.Diagnostics.Debug.WriteLine(msg.ToString());
}
return IntPtr.Zero;
}
}
当InitializeTimer方法在一个对话框中执行时,GetView的结果是null,因此自动退出定时器不会启动,应用程序也不会退出。
如果我做错了什么请告诉我
你有两个潜在的问题:
-
当一个视图模型被实例化时,视图还没有被附加。CMs绑定系统会为您启动并连接所有内容,但是有几个步骤—在构造函数时绑定所有内容是不可能的。在你的VM上重写
OnViewAttached
-
如果你看一下
WindowManager
的实现,你会发现它实际上确保了它为你绑定的VM解析的视图被包装在一个窗口中。这意味着GetView()
实际上返回给定VM的视图,这可能不一定是一个窗口。
取决于您是创建UserControls
还是实际的Window
控件,结果仍然可能不正确。我怀疑如果你对问题1进行排序。你可能会遇到问题2。
如果是这样的话,你只需要解析视图的Parent
来获得容纳它的Window
。
编辑:为了获得视图的父元素,你可以使用基础类型FrameworkElement
,它表示一个逻辑元素——它有一个Parent
属性,指向元素的逻辑父元素
您可以在OnViewAttached
中使用如下内容:
override OnViewAttached()
{
var view = GetView();
// Cast the window
var window = view as Window;
// If the control wasn't a window
if(window == null)
{
// Cast to FrameworkElement
var fe = view as FrameworkElement;
// If it's null throw
if(fe == null) throw new Exception("View was not present");
// Otherwise try and cast its parent to a window
window = fe.Parent as Window;
// If no window, throw
if(window == null) throw new Exception("Window could not be found");
}
// Do stuff
}
您可以将其作为IViewAware
public static class IViewAwareExtensions
{
public static Window TryGetParentWindow(this IViewAware viewAware)
{
var view = viewAware.GetView();
// Cast the window
var window = view as Window;
// If the control wasn't a window
if(window == null)
{
// Cast to FrameworkElement
var fe = view as FrameworkElement;
// Return null if not found
if(fe == null) return null;
// Otherwise try and cast its parent to a window
window = fe.Parent as Window;
// If no window, return null
if(window == null) return null;
}
}
return window;
}
然后在OnViewAttached
:
var window = this.TryGetParentWindow();