我正在使用Calibun Micro框架编写WPF应用程序。它实现了一个自动签名系统,该系统会在一段预定义的不活动时间后自动将用户签出应用程序。我使用here找到的方法检查是否不活动。
我在我的应用程序中创建对话框(使用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,因此自动注销计时器不会启动,应用程序也不会注销。
请告知我是否做错了。
答案 0 :(得分:1)
您有两个潜在问题:
实例化视图模型时,尚未附加视图。 CM绑定系统启动并为您提供所有内容,但有几个步骤 - 在构造函数时间内绑定所有内容是不可能的。而是覆盖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();