Xamarin:ItemsControl.ItemsSourceプロパティとバインドした配列を別スレッドから動かす
WPFでもあった問題なのですが、(async/awaitなどを用いるなどして)メインではないスレッドから、ItemsControlのItemsSourceプロパティにバインドしたObservableCollectionに操作を行おうとするとエラーとなります。
(上記エラーはUWPプロジェクト、Windows8.1プロジェクトで確認)
xaml(View)
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="asyncawait_test.Page1" xmlns:local="clr-namespace:asyncawait_test"> <ContentPage.BindingContext> <local:ViewModel /> </ContentPage.BindingContext> <StackLayout Orientation="Vertical"> <Button Text="test" Command="{Binding MyCommand}" /> <ListView ItemsSource="{Binding MyList}" /> </StackLayout> </ContentPage>
ViewModel(一部抜粋)
public const string MyListPropertyName = "MyList"; private ObservableCollection<string> _myList = new ObservableCollection<string>(); /// <summary> /// ListViewのItemsSource /// </summary> public ObservableCollection<string> MyList { get { return _myList; } set { if (_myList == value) { return; } _myList = value; RaisePropertyChanged(MyListPropertyName); } } private RelayCommand _myCommand; /// <summary> /// ボタンのコマンド /// </summary> public RelayCommand MyCommand { get { return _myCommand ?? (_myCommand = new RelayCommand( async () => { await Task.Factory.StartNew(TestMethod); })); } } //awaitで呼び出されるため別スレッドで実行されるメソッド private void TestMethod() { //エラー MyList.Add("aaa"); }
WPFではDispacherを用いて解決しておりましたが、XamarinではDevice.BeginInvokeOnMainThreadメソッドを用いて解決するとよさそうです。
//awaitで呼び出されるため別スレッドで実行されるメソッド private void TestMethod() { //これならOK Device.BeginInvokeOnMainThread(() => MyList.Add("aaa")); }