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 の結果が null になるため、自動サインオフ タイマーは開始されず、アプリケーションはサインオフしません。

私が何か間違ったことをしている場合は、アドバイスしてください。

4

1 に答える 1

1

次の 2 つの潜在的な問題があります。

  1. ビューモデルがインスタンス化されるとき、ビューはまだアタッチされていません。CM バインディング システムが起動し、すべてをフックしますが、いくつかの手順があります。コンストラクター時にすべてをバインドすることは不可能です。OnViewAttached代わりに、VM でオーバーライドします

  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 に答える