2

オブジェクトの状態を管理するオブジェクトがありSessionます(nhibernateセッションと同様)。このセッションは、内部セッション状態の更新を必要とする可能性のある外部ソースからのイベントをリッスンします。アクセスされるデータが一貫していることを確認するために、セッションにロックを実装しようとしましたが、非常に多くの厄介なエッジケースがあります。

代わりに、セッション(UIスレッド)を使用しているのと同じスレッドにこれらのイベントをマーシャリングする方が簡単な場合があります。通常、これはで行われControl.Invoke()ますが、これはデータオブジェクトであるためControl、アクセスすることはできません。

これは合理的なアプローチですか?セッション状態を更新する前に、このイベントをUIスレッドに取り込むにはどうすればよいですか?セッションの作成時に、を使用しDispatcherて現在のスレッドのディスパッチャーをキャプチャできますか?

4

2 に答える 2

1

ビュー ( UI ) によってキャッチされるイベントをビジネス オブジェクトに発生させ、そのイベント ハンドラーでマーシャリングを実行するのでControl、呼び出しが必要かどうかをその場所で理解する必要があります。

public static class ControlExtentions
    {
        public delegate void InvokeHandler();
        public static bool SafeInvoke(this Control control, InvokeHandler handler)
        {
            if (control.InvokeRequired)
            {
                try
                {
                    control.Invoke(handler);
                }
                finally { }
                return false;
            }
            else
                handler.Invoke();
            return true;
        }

    }

WPF を使用している場合は、CaliburnMicro からインスピレーションを得ることができます。

public static class Execute
    {
        private static Action<System.Action> executor = action => action();

        /// <summary>
        /// Initializes the framework using the current dispatcher.
        /// </summary>
        public static void InitializeWithDispatcher()
        {
#if SILVERLIGHT
            var dispatcher = Deployment.Current.Dispatcher;

            executor = action => {
                if(dispatcher.CheckAccess())
                    action();
                else {
                    var waitHandle = new ManualResetEvent(false);
                    Exception exception = null;
                    dispatcher.BeginInvoke(() => {
                        try {
                            action();
                        }
                        catch(Exception ex) {
                            exception = ex;
                        }
                        waitHandle.Set();
                    });
                    waitHandle.WaitOne();
                    if(exception != null)
                        throw new TargetInvocationException("An error occurred while dispatching a call to the UI Thread", exception);
                }
            };
#else
            var dispatcher = Dispatcher.CurrentDispatcher;

            executor = action => {
                if(dispatcher.CheckAccess())
                    action();
                else dispatcher.Invoke(action);
            };
#endif

        }

        /// <summary>
        /// Resets the executor to use a non-dispatcher-based action executor.
        /// </summary>
        public static void ResetWithoutDispatcher() {
            executor = action => action();
        }

        /// <summary>
        /// Executes the action on the UI thread.
        /// </summary>
        /// <param name="action">The action to execute.</param>
        public static void OnUIThread(this System.Action action) {
            executor(action);
        }
    }
于 2011-07-04T09:16:01.127 に答える
1

通常、ロックは非常に簡単で、最良のオプションであると思います。必要なものを正しく実装することは、おそらくはるかに困難です (そして、「厄介なエッジ ケース」がないわけではありません)。

ただし、.Net 4の既存の実装を使用BlockingCollection<T>して、シングル スレッドでデキューすることができます。残念ながら、そのスレッドはブロックされるため、UI スレッドを使用することはできません。

于 2011-07-04T09:47:01.413 に答える