获取Hwnd.FromHwnd对话框的容器窗口



我正在使用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,因此自动退出定时器不会启动,应用程序也不会退出。

如果我做错了什么请告诉我

你有两个潜在的问题:

  1. 当一个视图模型被实例化时,视图还没有被附加。CMs绑定系统会为您启动并连接所有内容,但是有几个步骤—在构造函数时绑定所有内容是不可能的。在你的VM上重写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();

相关内容

  • 没有找到相关文章

最新更新