Chris W.
Chris W.

Reputation: 23280

ListBox Item returns conflicting property to children

So I'm stumped at the moment, and hoping another pair of eyes can catch what I'm missing or at least point me in a direction to dig further. Sorry in advance, I don't often ask quick and easy questions.

Scenario: Huge silverlight solution with some precarious parts to it they want built on with new features but no large effort rewrites or anything. One of which being a virtualized ListBox. This ListBox is a parent to many different things in ways I wouldn't normally expect to see done the way they were. So to give a little visualization of the hierarchy in pseudo;

ListBox (Parent)

-ListBoxItemTemplate --A user control that hosts a ContentControl where other UserControls are swapped out in it.

---Multiple other UserControls that get swapped out in the previous ContentControl at runtime based on numerous conditions.

----Within each nested UserControl there's often other nested ItemsControls and collections of sorts with their Item Template.

Hopefully I've still got your understanding on this monster but if not, here's something a little more visual to help convey the issue I'm getting to; enter image description here

So here's my current issue. Based on what they want, without doing some major refactoring I'm trying to make lemonade and use the SelectedItem bool from the parent listbox to perform some things in some of these sub-view UserControls.

I do this with a quick ancestor grab for the IsSelected of the parent ListBoxItem. I do this (xaml wise) via a quick {Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}} from the sub UserControls.

Which works as expected in most cases and returns True/False just fine to do what it needs to do. However in some cases when other various UserControls are acting as the item then it may return True as IsSelected to the first level nested UserControl, but False to one of the sub-nested UserControls. Or vice versa. The funny thing is, it isn't consistent at all.

For example say I load 20 items. All using the exact same structure of nested controls. I'll get weird results back where say 18 of the items will return True, and maybe 2 return False. Which in a basic explanation means say I select one ListBoxItem. Everything is returned as expected, everything does what it's supposed to do. HOWEVER, I'll select another ListBoxItem from the same list, that's using all the exact same parts and the outermost parent element will return the property for the expected selected item....BUT THEN an entirely different item on the list will receive the property also.

Or to help visualize. Imagine you're looking at a listbox, you select an item and stuff inside it appears. You select another and the same thing happens as expected. You select another from the top of the list, and an item at the bottom of the list will display the action meant for what you've selected. The item you meant to select will still return Focused and display as focused, except an entirely different item you haven't touched gets the action result and throws the bool to True when it should be False.

Hopefully I haven't lost you in this mess. My question is what the hell might cause this kind of behavior? Do any alarm bells go off (besides the obvious ones) for you?

There are no other ListBox controls used anywhere else in there. I'm not even sure exactly what to look for? Maybe it's just a bug in the ancestor relationship binding in Silverlight? Maybe some weird naming collision or something? I'm not sure and troubleshooting has become the bane of my existence, but I'm limited on options considering if it were my choice. I'd rip all this crap out and do it in a way that made more sense.

Either way, thanks for letting me borrow some brain time considering how confusing I'm sure this is for anybody. :)

Upvotes: 4

Views: 173

Answers (2)

Martin
Martin

Reputation: 6156

To me this sounds like your ancestor-type-chain (this term is totally made up) looks different for different items, and therefore your ancestor binding yields for some items an ancestor that was not expected (different level in the hierarchy).

enter image description here

You can try the following: Add a BindableObjectReference to the resources of your ItemTemplate or your ItemContainerStyle.Template and replace you ancestor binding with a binding to this newly added resource. This way you can be sure to hit the correct level in the hierarchy.

<ListBox.ItemTemplate>
    <DataTemplate>
        <Grid...>
          <Grid.Resources>
            <BindableObjectReference x:Key="TopLevelListBoxItem"
              Object="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}}"/>
          </Grid.Resources>
          ...
        </Grid>
    </DataTemplate>
</ListBox.ItemTemplate>


<MyNestedSubControl
  ...
  Foo="{Binding Path=Object.IsSelected, Source={StaticResource TopLevelListBoxItem}}"
  .../>

the code for BindableObjectReference:

public class BindableObjectReference : DependencyObject
{
    public object Object
    {
        get { return GetValue( ObjectProperty ); }
        set { SetValue( ObjectProperty, value ); }
    }

    public static readonly DependencyProperty ObjectProperty =
        DependencyProperty.Register( "Object", typeof( object ),
        typeof( BindableObjectReference ), new PropertyMetadata( null ) );
}

If this does not work: Another cause might be the virtualization. Try to disable virtualization and see if the issue still exists.

Upvotes: 2

momar
momar

Reputation: 364

Just adding some additional information here.

The FindAncestor, AncestorType will look at base classes as well. Given that ListBoxItem is the base class for ComboBoxItem and ListViewItem it may be possible that it's fetching the value from the incorrect control.

Upvotes: 0

Related Questions