-1

Observable Lists を使用するアプリを作成しました。私は ObservableList クラスをスレッドセーフにしました (私が思うに)、それは私のアプリケーションでうまく機能しています。

今、アプリケーションをサービスとしてインストールしようとしています。何かがリストに追加されるまでは、これも問題なく機能します。そこのスレッドは死んでいると思います。私は次のコードを持っています:

/// <summary>
/// Creates a new empty ObservableList of the provided type. 
/// </summary>
public ObservableList()
{
    //Assign the current Dispatcher (owner of the collection) 
    _currentDispatcher = Dispatcher.CurrentDispatcher;
}

/// <summary>
/// Executes this action in the right thread
/// </summary>
///<param name="action">The action which should be executed</param>
private void DoDispatchedAction(Action action)
{
    if (_currentDispatcher.CheckAccess())
        action.Invoke();
    else
        _currentDispatcher.Invoke(DispatcherPriority.DataBind, action);
}

/// <summary>
/// Handles the event when a collection has changed.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    DoDispatchedAction(() => base.OnCollectionChanged(e));
}

Collection.Add(object)デバッグ中に、が呼び出されているのを見てきました。関数を開始しDoDispatchedAction、デバッガーが最後にヒットするのは_currentDispatcher.Invoke(DispatcherPriority.DataBind, action);. この後、アプリケーションは続行されますが、その後のコードCollection.Add(object)は実行されなくなります。最初に項目を ObservableList に追加したコードも続行されません。そういうわけで、スレッドが死ぬか、そのようなものだと思います。

デバッガーで動作を確認したところ、次のメッセージが表示されていました。

ApartmentState = '_currentDispatcher.Thread.ApartmentState' がタイプ 'System.Threading.ThreadStateException' の例外をスローしました

どうすればこの問題を解決できますか? 私は正しい方向に考えていますか?

4

2 に答える 2

1

私の理解では、Windows サービスとして実行する必要があるコア コードと、同じコア コードを使用する WPF アプリケーションがあります。

したがって、基本的には、ソリューションに 3 つのプロジェクトのようなものが必要です。

  • ハードウェア関連のジョブを実行するコア アセンブリ
  • Windows サービスとしてインストールされる実行可能ファイル。この実行可能ファイルはコア アセンブリを参照します
  • コア アセンブリも参照する WPF アプリケーション

ディスパッチャは、アクションを UI スレッドにマーシャリングするのに役立ちます。これは基本的に、WPF アプリケーションの UI スレッドでコードを実行するために使用されます。たとえば、コレクションを にバインドする場合、バインドによって UI が更新されるため、UI スレッドでイベントを発生させる必要がありますDataGridCollectionChangedまた、UI スレッドから UI を更新する必要があります。

更新する UI がないため、コア アセンブリでディスパッチャーを処理する必要はありません。CollectionUI コンポーネントにバインドしないため、ここでは simple を使用できます。Windows サービスの実行可能ファイルについても同じです。

一方、WPF アプリケーションでは、ObservableCollectionバインドされた UI コンポーネント (DataGridたとえば) を使用できます。このアセンブリでのみ、UI コンポーネントが常に UI スレッドから更新されるようにする必要があります (つまり、そのために が必要Dispatcherです)。

したがって、コード例:

コア アセンブリ:

public IEnumerable<SomeClass> GetHardwareInfo()
{
    return new List<SomeClass> { ... };
}

Windows サービスの実行可能ファイル:

internal static void Main(string[] args)
{
    ...
    var objs = new MyCoreInstance().GetHardwareInfo();
    ...
}

WPF アプリケーション (ViewModel としましょう):

// Some UI component is binded to this collection that is obersvable
public ObservableCollection<SomeClass> MyCol
{
    get
    {
        return this.myCol;
    }

    set
    {
        if (this.myCol != value)
        {
            this.myCol = value;
            this.RaisePropertyChanged("MyCol");
        }
    }
}

public void UpdateList()
{
    var info = new MyCoreInstance().GetHardwareInfo();

    // Now, marshall back to the UI thread to update the collection
    Application.Current.Dispatcher.Invoke(() =>
        {
            this.MyCol = new ObservableCollection(info);
        });
}
于 2013-04-29T12:24:30.137 に答える