PG.Lib

アプリ開発関連とかガジェット関連とか

データバインディングしたGirdView で非同期にデータ追加するとエラーになる

結論から言うと Dispatcher する。

INotifyPropertyChanged を実装したクラスがあるとして

public class hoge : INotifyPropertyChanged
{
    private string _name;
    public string name 
    {
        get { return _name; }
        set 
        { 
            _name = value;
            NotifyPropertyChanged("name");
        }
    }

    #region 通知
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion
}

 

ObservableCollection<hoge> なリストのクラスを作る。ビューモデル的な。

public class HogeList : INotifyPropertyChanged
{
    ObservableCollection<hoge> _hoges;
    public ObservableCollection<hoge> Hoges
    {
        get
        {
            return _hoges;
        }
    }

    public void AddHoge(hoge value)
    {
        _hoges.Add(value);
        NotifyPropertyChanged("Hoges");
    }

    #region 通知
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion
}

 

GridView / ListView にバインド。

var hoge = new HogeList();

this.DataContext = hoge.Hoges;

 

非同期的なタイミング(自分の場合、TCPの受信)で列を追加。

void _listener_ConnectionReceived(Windows.Networking.Sockets.StreamSocketListener sender, Windows.Networking.Sockets.StreamSocketListenerConnectionReceivedEventArgs args)
{
    // データ受信的な処理

    hoge.AddHoge(受信データ);
}

 

 

で、実行したらリストクラスの PropertyChanged でエラーになった。

型 'System.Runtime.InteropServices.COMException' の例外が System.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした 追加情報:アプリケーションは、別のスレッドにマーシャリングされたインターフェイスを呼び出しました。 (HRESULT からの例外:0x8001010E (RPC_E_WRONG_THREAD))

 

UIにバインドしているので、スレッドセーフな動作にしておく必要があるのかな?

こちらの記事を参考にして解決。

 

受信時の処理に Dispatcher.RunAsync を差し込む。

void _listener_ConnectionReceived(Windows.Networking.Sockets.StreamSocketListener sender, Windows.Networking.Sockets.StreamSocketListenerConnectionReceivedEventArgs args)
{
    // データ受信的な処理

    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, delegate
    {
        hoge.AddHoge(受信データ);
    });
}

 

一応これで解決。