2

我正在使用 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 的结果为空,因此自动注销计时器不会启动,应用程序也不会注销。

请告知我是否做错了什么。

4

1 回答 1

1

你有两个潜在的问题:

  1. 实例化视图模型时,视图尚未附加。CM 绑定系统启动并为您连接所有内容,但有几个步骤 - 在构造函数时绑定所有内容是不可能的。而是覆盖OnViewAttached您的虚拟机

  2. 如果您查看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();
于 2013-04-30T13:38:13.990 回答