У меня есть связанное свойство по классу, Foo
, который определяется аналогично как следует (отредактированный для ясности),Как уведомлять изменения для связанного свойства, которое полностью зависит от ObservableCollection?
public class Foo : INotifyPropertyChanged
{
public Foo()
{
// This should notify when IsHidden changes?
MyApp.ViewModel.HiddenCategories.CollectionChanged += (s, e) => {
this.NotifyPropertyChanged("IsHidden");
};
}
public CategoryId Category { get; set; }
// IsHidden depends on a `global' ObservableCollection object on the ViewModel
public bool IsHidden
{
get { return MyApp.ViewModel.HiddenCategories.Contains(this.Category); }
}
// IsHidden is toggled by adjusting the global ObservableCollection - how to notify the UI?
public void ToggleHidden()
{
if (this.IsHidden)
MyApp.ViewModel.HiddenCategories.Remove(this.Category);
else
MyApp.ViewModel.HiddenCategories.Add(this.Category);
}
#region INotifyPropertyChanged members
...
}
ViewModel имеет следующие определенные на нем,
public class FooRegion
{
public string RegionName { get; set; }
// Foos is bound in the top ListBox DataTemplate
// Each Foo has properties bound in the sub ListBox DataTemplate
public ObservableCollection<Foo> Foos { get; set; }
}
// This is actually what is bound to the top level ListBox
public ObservableCollection<FooRegion> FoosByRegion { get; set; }
public ObservableCollection<CategoryId> HiddenCategories { get; set; }
Мой XAML определяет два ItemTemplates
в ресурсах следующим образом,
<phone:PhoneApplicationPage.Resources>
...
<DataTemplate x:Key="MainItemTemplate">
<StackPanel >
<TextBlock Text="{Binding Name}"/>
<ListBox ItemsSource="{Binding Foos}"
ItemTemplate="{StaticResource SubItemTemplate}" />
</StackPanel>
</DataTemplate>
...
<DataTemplate x:Key="SubItemTemplate">
<StackPanel Opacity="{Binding IsHidden, Converter={StaticResource BoolToOpacity}}" >
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="{Binding IsHidden, ConverterParameter=unhide foo|hide foo,
Converter={StaticResource BoolToStrings}}" Tap="toggleHideFooContextMenuItem_Tap" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="Some Text Here"/>
</StackPanel>
</DataTemplate>
...
</phone:PhoneApplicationPage.Resources>
Эти ресурсы призваны к «вложенными» ListBox как е ollows,
<ListBox ItemTemplate="{StaticResource MainItemTemplate}" ItemsSource="{Binding FoosByRegion}" />
Этот метод, как представляется, только работа по частям, некоторые Foo
объекты обновляются в пользовательском интерфейсе, но другие не являются - как если бы уведомление не доходит до пользовательского интерфейса.
Как мне решить эту проблему?
Я не думаю, что это «гонка», это проблема - вы отлаживали ее, чтобы увидеть, куда она идет/когда (просто установите точки останова, и вы увидите ее). Я думаю, что более вероятно, что вы, например. «перезагружать» коллекцию где-то - и не переделывать события (вы должны делать оба - = + =) - или не запускать изменение GUI обратно в коллекцию (хотя и менее вероятно). Это зависит от того, как вы меняете коллекцию. Также это событие может обнаруживать только добавленные элементы, удаленные - не отдельные изменения - см. Это [ссылка] (http://stackoverflow.com/questions/4588359/implementing-collectionchanged) – NSGaga
GUI вызывает метод ToggleHidden() на 'Foo', который добавляет или удаляет' this.Category' (который представляет собой enum) из 'MyViewModel.HiddenCategories'. Мне не интересно запускать события на объектах перечисления, только когда элемент удаляется или добавляется. Отладка, кажется, имеет смысл, теперь кажется, что 'IsHidden' не обновляется в пользовательском интерфейсе ... – Brendan
Сделать IsHidden также« сеттер ». Возможно, у вас есть какой-то «сложный» путь к Foo.IsHidden - или так. Если вы опубликуете больше кода/XAML, я посмотрю завтра, приветствую. – NSGaga