TableCreek
TableCreek

Reputation: 799

ListView in Listview - SelectedIndex of parent not set when selecting child

I have a UI which displays a ListView in a ListView:

<ListView
    SelectedIndex="{x:Bind ParentViewModel.SelectedParentIndex, Mode=TwoWay}"
    ItemsSource="{x:Bind ParentViewModel.ParentViewModels, Mode=OneWay}">

    <ListView.ItemTemplate>
        <DataTemplate x:DataType="viewModels:ParentViewModel">
            <StackPanel>
                <TextBlock Text="{Binding ParentName}" />
        
                <ListView
                    SelectedIndex="{x:Bind SelectedChildIndex, Mode=TwoWay}"
                    ItemsSource="{Binding ChildViewModels, Mode=OneWay}">

                    <ListView.ItemTemplate>
                        <DataTemplate x:DataType="viewModels:ChildViewModel">

                        <TextBlock Text="{Binding ChildName}" />
                            
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

When I click on a parent element the SelectedParentIndex gets set and when I click on a child element the SelectedChildIndex gets set.

My problem is that when I click on a child element I don't know to which parent element it belongs because the SelectedParentIndex is not set. How can I solve this?

And the flow how it should be:enter image description here

Upvotes: 1

Views: 333

Answers (1)

DotNetRussell
DotNetRussell

Reputation: 9867

Just add an event in. Here is a compiled working example.

        <ListView
            ItemsSource="{Binding ParentViewModels, Mode=OneWay}"
            SelectedIndex="{Binding SelectedParentIndex, Mode=TwoWay}"
            SelectedItem="{Binding SelectedParent,Mode=TwoWay}">

            <ListView.ItemTemplate>
                <DataTemplate >
                    <StackPanel>
                        <TextBlock Text="{Binding ParentName}" />

                        <ListView                        
                        ItemsSource="{Binding ChildViewModels, Mode=OneWay}"
                        SelectedIndex="{Binding SelectedChildIndex, Mode=TwoWay}"
                        SelectedItem="{Binding SelectedChild,Mode=TwoWay}">   

                            <ListView.ItemTemplate>
                                <DataTemplate>

                                    <TextBlock Text="{Binding ChildName}" />

                                </DataTemplate>
                            </ListView.ItemTemplate>
                        </ListView>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

Here are the cs files. Please pay close attention to the structure.

The MasterViewModel is your DataContext for your View. It handles the SelectedParent, the SelectedParentIndex and your parents collection.

      public class MasterViewModel : ViewModelBase
      {
        private ParentViewModel _SelectedParent;

        public ParentViewModel SelectedParent
        {
            get { return _SelectedParent; }
            set 
            { 
                _SelectedParent = value; 
                OnPropertyChanged("SelectedParent"); 
            }
        }

        private int _SelectedParentIndex;

        public int SelectedParentIndex
        {
            get { return _SelectedParentIndex; }
            set 
             { 
                 _SelectedParentIndex = value; 
                 OnPropertyChanged("SelectedParentIndex"); 
             }
        }

        public ObservableCollection<ParentViewModel> ParentViewModels
        {
            get; private set;
        }

        public MasterViewModel()
        {
            ParentViewModels = new ObservableCollection<ParentViewModel>();
            LoadData();
        }

        private void LoadData()
        {
            for(int x = 0; x < 10; x++)
            {
                ParentViewModel parent = new ParentViewModel();
                parent.ChildChangedEvent += Parent_ChildChangedEvent;
                for(int y = 0; y < 20; y++)
                {
                    ChildViewModel child = new ChildViewModel() 
                                         { ChildName = "Child " + y };
                    parent.ChildViewModels.Add(child);
                }
                ParentViewModels.Add(parent);
            }
        }

        private void Parent_ChildChangedEvent(object sender, EventArgs e)
        {
            SelectedParent = (ParentViewModel)sender;
        }
    }

Your ParentViewModel contains your SelectedChildIndex, your SelectedChild and your ChildViewModels collection. It also has a name property

Notice that I added an EventHandler to your ParentViewModel. When the SelectedChild is updated, it fires the event off. Then, we handle this event in the MasterViewModel where we can force the SelectedParent to update.

    public class ParentViewModel : ViewModelBase
    {
        public String ParentName { get; set; }

        private int _SelectedChildIndex;

        public int SelectedChildIndex
        {
            get { return _SelectedChildIndex; }
            set 
            { 
               _SelectedChildIndex = value; 
               OnPropertyChanged("SelectedChildIndex"); 
            }
        }

        private ChildViewModel _SelectedChild;

        public ChildViewModel SelectedChild
        {
            get { return _SelectedChild; }
            set
            {
                _SelectedChild = value;
                OnPropertyChanged("SelectedChild");
                if (ChildChangedEvent != null)
                {
                    ChildChangedEvent(this, new EventArgs());
                }
            }
        }

        public ObservableCollection<ChildViewModel> ChildViewModels
        {
            get; private set;
        }

        public event EventHandler ChildChangedEvent;

        public ParentViewModel()
        {
            ChildViewModels = new ObservableCollection<ChildViewModel>();
        }
    }

Your ChildViewModel just has a name property.

    public class ChildViewModel : ViewModelBase
    {
        private string _childName;

        public string ChildName
        {
            get { return _childName; }
            set 
            { 
              _childName = value; 
              OnPropertyChanged("ChildName"); 
            }
        }

    }

The ViewModelBase just updates the UI

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        }
    }

enter image description here

enter image description here

enter image description here

Upvotes: 2

Related Questions