CollectionView にバインドされた ComboBox がある場合。そのCollectionViewでREFRESHを発行し、特定のアイテムを除外して、選択したアイテムの位置を変更し、コレクションのサイズをSelectedItemIndexより小さくします。次に、コンボボックスを使用できない状態のままにします。以下サンプルより
- 選択したアイテムを設定するボタンが押されます
- 次に、コレクションビューで更新を発行します
- 視覚的にはすべてが素晴らしいように見えます...コンボボックスでは、選択されたアイテムとして5が表示されるためです
- コンボボックスをクリックすると、迷惑なエラーでSLがクラッシュします
私はそれを ComboBox の一部までたどり、それを開くと SelectedItemIndex をメソッド SetContentPresenter に渡します。しかし、SelectedItemIndex が間違っているため、クラッシュします :-(
これが私のView Modelコードです
public class MainPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<DataObject> ItemSource;
public ICollectionView CollectionView { get; set; }
public MainPageViewModel()
{
ItemSource = new ObservableCollection<DataObject>();
var source = new CollectionViewSource();
for (int i = 0; i < 10; i++ )
{
ItemSource.Add(new DataObject(){ Id = i, Description = i.ToString()});
}
Filters = new List<string>();
source.Source = ItemSource;
CollectionView = source.View;
CollectionView.Filter = (x) =>
{
if (Filters.Count == 0)
return true;
return Filters.Contains((x as DataObject).Description);
};
}
public event PropertyChangedEventHandler PropertyChanged;
internal void ButtonPushed()
{
SelectedObject = ItemSource.First(x => x.Description == "5");
Filters.Add("1");
Filters.Add("5");
CollectionView.Refresh();
}
public List<string> Filters
{
get;
set;
}
DataObject _SelectedObject;
public DataObject SelectedObject
{
get
{
return _SelectedObject;
}
set
{
if (_SelectedObject != value)
{
_SelectedObject = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("SelectedObject"));
}
}
}
型式コード
public class DataObject
{
public int Id { get; set; }
public string Description { get; set; }
public override string ToString()
{
return Description;
}
}
コードを表示
<StackPanel x:Name="LayoutRoot" Background="White">
<ComboBox ItemsSource="{Binding CollectionView}" SelectedItem="{Binding SelectedObject, Mode=TwoWay}"></ComboBox>
<Button Content="Run Test" Click="Button_Click_1"></Button>
</StackPanel>
コードビハインド
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = new MainPageViewModel();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var vm = DataContext as MainPageViewModel;
Dispatcher.BeginInvoke(() =>vm.ButtonPushed());
}
}
コンボボックスのselecteditemで双方向バインディングを行うのではなく、代わりにCollectionViewのCurrentItemをVMとコンボボックス間の通信経路として使用することで、プロジェクトでこれを回避しました。このようにして、更新を発行する前に現在のアイテムを null にすることができます。その後、コンボボックスを一貫した状態に保つ現在のアイテムを設定できます。
アプリケーションでは、このコンボボックスはカスケード コンボボックスの実装の一部です。そのため、別のコンボボックスで 1 つの項目を選択すると、別のコンボボックスがフィルターダウンされますが、既に選択されている項目は依然として実行可能なオプションである可能性があります。