0

I have a bound property on a class, Foo which is defined similar to as follows (edited for clarity),

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
    ...

}

The ViewModel has the following defined on it,

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; }

My XAML defines two ItemTemplates in the resources as follows,

<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>

These resources are called on to a 'nested' ListBox as follows,

<ListBox ItemTemplate="{StaticResource MainItemTemplate}" ItemsSource="{Binding FoosByRegion}" />

This method appears to only work piecemeal, Some Foo objects are updated in the UI, but others are not - as if the notification is not reaching the UI.

How should I be tackling this problem?

Brendan
  • 18,771
  • 17
  • 83
  • 114
  • I don't think it's the 'race' that's the problem - did you debug to see where it goes/when (just set breakpoints and you should see it). I think more likely is that you're e.g. 'resetting' the collection somewhere - and not rewiring the events (you should be doing both -= +=) - or not triggering the GUI change back to collection (though less likely to happen). It depends on how is that you're changing collection. Also that event can only detect items 'added', deleted - not individual changes - see this [link](http://stackoverflow.com/questions/4588359/implementing-collectionchanged) – NSGaga-mostly-inactive Apr 01 '13 at 00:10
  • The GUI calls a `ToggleHidden()` method on `Foo` which adds or removes a `this.Category` (which is infact an enum) from `MyViewModel.HiddenCategories`. I'm not interested in triggering events on the enum objects, just on when an item is removed or added. The debug seems to make sense, it now appears that `IsHidden` is not updating in the UI ... – Brendan Apr 01 '13 at 01:57
  • Make IsHidden have a 'setter' as well. Maybe you have some 'composite' path to Foo.IsHidden - or so. If you post more code / XAML I'll take a look tomorrow, cheers. – NSGaga-mostly-inactive Apr 01 '13 at 02:08
  • I've included more details - perhaps what could be important is that I have an `ObservableCollection` of objects each of which contain an `ObservableCollection` ... – Brendan Apr 01 '13 at 12:02
  • 'this.NotifyPropertyChanged("IsHidden");' try moving it to `ToggleHidden` directly - and check if you ever call that toggle method (debug) - and whether it adds/removes that properly. Also put a break on IsHidden 'getter' to see if after you notify 'someone' is actually in on it. It may be how you 'initialize' collections (and even more if a hierarchy) - only once or if you ever 'anull' and recreate - then you'll lose the events. You have a bit 'unfortunate' MVVM - you're calling 'up' for that list- I'd make 'hidden' part of category (complex) - and not add/remove - but hide cat based on flag – NSGaga-mostly-inactive Apr 01 '13 at 12:39
  • I got it! Turned out that activating the `ContextMenu` adjusts the opacity of the object - the same property which I was adjusting when `IsHidden` was changed (I updated the question accordingly) - the animation overwrote my own change making me think the UI had not updated for one of my objects ... – Brendan Apr 01 '13 at 14:44
  • great that you did - let me know if you'd want me to post my 'part of the answer' (if it did help you reach to solution - so others can see) - or just answer yourself - but you should close it – NSGaga-mostly-inactive Apr 01 '13 at 15:29

1 Answers1

0

ContextMenu from the Windows Phone Toolkit applies an animation which affects the opacity of the surrounding elements. Applying the opacity to the child elements individually solved the problem.

Brendan
  • 18,771
  • 17
  • 83
  • 114