わかりましたので、この質問は Windows Phone 7/Silverlight (更新された WP7 ツール、2010 年 9 月) に関連しており、具体的には基になるObservableCollection<T>
.
WP7 テンプレートのピボット コントロール アプリケーションをいじっていると、 の基になる項目を変更してもObservableCollection<T>
、画面上の ListBox が更新されないという問題に遭遇しました。基本的に、サンプル アプリには 2 つのピボットがあり、1 つ目は基になるObservableCollection<T>
に直接バインドされ、2 つ目は にバインドされますCollectionViewSource
(つまり、基になる のフィルター処理されたビューを表しますObservableCollection<T>
)。
次のように、 ObservableCollection<T>
implementに追加されている基になるアイテム。INotifyPropertyChanged
public class ItemViewModel : INotifyPropertyChanged
{
public string LineOne
{
get { return _lineOne; }
set
{
if (value != _lineOne)
{
_lineOne = value;
NotifyPropertyChanged("LineOne");
}
}
} private string _lineOne;
public string LineTwo
{
get { return _lineTwo; }
set
{
if (value != _lineTwo)
{
_lineTwo = value;
NotifyPropertyChanged("LineTwo");
}
}
} private string _lineTwo;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
} private bool _isSelected = false;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
次に、メイン クラスで、データ コレクションが作成されます (簡潔にするためにリストを省略します。また、他の項目とは異なり、LoadData() エントリの 3 つが IsSelected == true であることに注意してください)。
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
}
public ObservableCollection<ItemViewModel> Items { get; private set; }
public bool IsDataLoaded
{
get;
private set;
}
public void LoadData()
{
this.Items.Add(new ItemViewModel() { LineOne = "runtime one", IsSelected = true, LineTwo = "Maecenas praesent accumsan bibendum" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime two", LineTwo = "Dictumst eleifend facilisi faucibus" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime three", IsSelected = true, LineTwo = "Habitant inceptos interdum lobortis" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime four", LineTwo = "Nascetur pharetra placerat pulvinar" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime five", IsSelected = true, LineTwo = "Maecenas praesent accumsan bibendum" });
this.Items.Add(new ItemViewModel() { LineOne = "runtime six", LineTwo = "Dictumst eleifend facilisi faucibus" });
this.IsDataLoaded = true;
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainPage.xaml ファイルでは、最初のピボットがリストItemSource
に直接基づいていObservableCollection<T>
ます。2 番目のピボット内では、画面上の ListBox のPropertyItemSource
が に設定されておりCollectionViewSource
、その基になるソースは上記で設定された に基づいています。ObservableCollection<T>
LoadData()
<phone:PhoneApplicationPage.Resources>
<CollectionViewSource x:Key="IsSelectedCollectionView" Filter="CollectionViewSource_SelectedListFilter">
</CollectionViewSource>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Pivot Control-->
<controls:Pivot Title="MY APPLICATION">
<!--Pivot item one-->
<controls:PivotItem Header="first">
<!--Double line list with text wrapping-->
<ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
<!--Pivot item two-->
<controls:PivotItem Header="second">
<!--Triple line list no text wrapping-->
<ListBox x:Name="SecondListBox" Margin="0,0,-12,0" ItemsSource="{Binding Source={StaticResource IsSelectedCollectionView}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineThree}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
</controls:Pivot>
</Grid>
<!--Sample code showing usage of ApplicationBar-->
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1" Click="ApplicationBarIconButton_Click"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="MenuItem 1"/>
<shell:ApplicationBarMenuItem Text="MenuItem 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
MainPage.xaml.cs では、上記のセクションのFilter
属性にフィルター ハンドラーが割り当てられていることに注意してください。フィルター ハンドラーは、 trueに設定された項目をふるいにかけます。CollectionViewSource
Resources
IsSelected
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
CollectionViewSource isSelectedListView = this.Resources["IsSelectedCollectionView"] as CollectionViewSource;
if (isSelectedListView != null)
{
isSelectedListView .Source = App.ViewModel.Items;
}
}
}
private void CollectionViewSource_SelectedListFilter(object sender, System.Windows.Data.FilterEventArgs e)
{
e.Accepted = ((ItemViewModel)e.Item).IsSelected;
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
ItemViewModel item = App.ViewModel.Items[App.ViewModel.Items.Count - 1];
item.IsSelected = !item.IsSelected;
}
}
また、データをロードした直後に を取得し、CollectionViewSource
そのデータ ソースをObservableCollection<T>
リストとして設定することにも注意してください。これは、フィルタリングを実行できるベース データがあるためです。
アプリケーションが読み込まれると、期待どおりにデータが表示され、true のアイテムがObservableCollection<T>
2IsSelected
番目のピボットに表示されます。
アプリケーション バー アイコンのコメントを外したことに気付くでしょう。最初のアイコンは、クリックIsSelected
されたときに最後の項目のプロパティを切り替えObservableCollection<T>
ます (MainPage.xaml.cs の最後の関数を参照)。
これが私の質問の要点です。該当するバー アイコンをクリックすると、リストの最後の項目のIsSelected
プロパティがいつ true に設定されているかがわかりますが、2 番目のピボットにはこの変更された項目が表示されません。ハンドラーがアイテムに対して起動されていることがわかりますがNotifyPropertyChanged()
、コレクションはこの事実を認識していません。そのため、ピボット 2 のリスト ボックスは、コレクションに新しいアイテムが追加されるはずであるという事実を反映して変化しません。
ここで非常に基本的な/基本的なものが欠けていると確信していますが、それができない場合、コレクションを取得する最良の方法を知っている人はいますか?
この問題は、フィルタリングだけでなくソートにも当てはまると思います ((aCollectionViewSource
がソートに基づいている場合、ソートで使用されるアイテムのプロパティが変更された場合、コレクションのソート順はこれを次のように反映する必要があるという意味で)良い))