2012-03-22 2 views
4

Я в настоящее время осуществляет приложение, которое отображает иерархии с помощью ListBoxes (пожалуйста, не предлагают использовать TreeView, ListBoxes необходимы).WPF MVVM иерархии выбран пункт

Похоже, что in the article: WPF’s CollectionViewSource (with source code).

enter image description here

Классы:

public class Mountains : ObservableCollection<Mountain> 
{ 
    public ObservableCollection<Lift> Lifts { get; } 

    public string Name { get; } 
} 

public class Lift 
{ 
    public ObservableCollection<string> Runs { get; } 
} 

В примере используется CollectionViewSource экземпляров (см XAML), чтобы упростить конструкцию. Экземпляр Mountains класс - это DataContext для окна.


Проблема: Я хотел бы, что Mountains класса иметь SelectedRun свойство и оно должно быть установлено в настоящее время выбран пробег.

public class Mountains : ObservableCollection<Mountain> 
{ 
    public ObservableCollection<Lift> Lifts { get; } 

    public string Name { get; } 

    public string SelectedRun { get; set; } 
} 

Возможно, я пропустил какой-то принципиальный принцип, но как я могу достичь этого?

ответ

4

Возможно, вы захотите ознакомиться с использованием «/» в привязках. См. Раздел «Указатели текущих позиций» на этом MSDN article.

Вот мое решение:

Xaml

<Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <Grid.ColumnDefinitions> 
     <ColumnDefinition/> 
     <ColumnDefinition/> 
     <ColumnDefinition/> 
    </Grid.ColumnDefinitions> 

    <TextBlock Margin="5" Grid.Row="0" Grid.Column="0" Text="Mountains"/> 
    <TextBlock Margin="5" Grid.Row="0" Grid.Column="1" Text="Lifts"/> 
    <TextBlock Margin="5" Grid.Row="0" Grid.Column="2" Text="Runs"/> 

    <ListBox Grid.Row="1" Grid.Column="0" Margin="5" 
      ItemsSource="{Binding Mountains}" DisplayMemberPath="Name" 
      IsSynchronizedWithCurrentItem="True" /> 

    <ListBox Grid.Row="1" Grid.Column="1" Margin="5" 
      ItemsSource="{Binding Mountains/Lifts}" DisplayMemberPath="Name" 
      IsSynchronizedWithCurrentItem="True"/> 

    <ListBox Grid.Row="1" Grid.Column="2" Margin="5" 
      ItemsSource="{Binding Mountains/Lifts/Runs}" 
      IsSynchronizedWithCurrentItem="True" 
      SelectedItem="{Binding SelectedRun}"/> 
</Grid> 

C# (обратите внимание, что вам не нужно осуществить INotifyPropertyChanged, если свойства не будут изменены, а не только выбран)

public class MountainsViewModel 
{ 
    public MountainsViewModel() 
    { 
     Mountains = new ObservableCollection<Mountain> 
         { 
          new Mountain 
           { 
            Name = "Whistler", 
            Lifts = new ObservableCollection<Lift> 
               { 
                new Lift 
                 { 
                  Name = "Big Red", 
                  Runs = new ObservableCollection<string> 
                     { 
                      "Headwall", 
                      "Fisheye", 
                      "Jimmy's" 
                     } 
                 }, 
                new Lift 
                 { 
                  Name = "Garbanzo", 
                  Runs = new ObservableCollection<string> 
                     { 
                      "Headwall1", 
                      "Fisheye1", 
                      "Jimmy's1" 
                     } 
                 }, 
                new Lift {Name = "Orange"}, 
               } 

           }, 
          new Mountain 
           { 
            Name = "Stevens", 
            Lifts = new ObservableCollection<Lift> 
               { 
                new Lift {Name = "One"}, 
                new Lift {Name = "Two"}, 
                new Lift {Name = "Three"}, 
               } 

           }, 
          new Mountain {Name = "Crystal"}, 
         }; 
    } 

    public string Name { get; set; } 
    private string _selectedRun; 
    public string SelectedRun 
    { 
     get { return _selectedRun; } 
     set 
     { 
      Debug.WriteLine(value); 
      _selectedRun = value; 
     } 
    } 

    public ObservableCollection<Mountain> Mountains { get; set; } 
} 

public class Mountain 
{ 
    public string Name { get; set; } 

    public ObservableCollection<Lift> Lifts { get; set; } 
} 

public class Lift 
{ 
    public string Name { get; set; } 

    public ObservableCollection<string> Runs { get; set; } 
} 
+0

Большое спасибо! Это именно то, что я хочу! Кстати, что, если у меня есть 'ICollectionView' вместо' ObservableCollection'? Я пробовал «ICollectionView», и решение отлично работает. Я из любопытства, есть ли способ получить 'SelectedRun' на' MountainsViewModel' без привязки 'ListBox' SelectedItem'?Может быть, как-то использовать свойства/события 'ICollectionView'? –

+0

WPF автоматически обертывает любую коллекцию в соответствующей реализации ICollectionView внутри, поэтому в конце нет большой разницы. Если SelectedRun является свойством зависимостей элемента управления (а не модели представления), вы можете привязать его к «Горам/Лифтам/Бегам /», обратите внимание на конец «/», ... возможно, я не пробовал. – Phil

+0

Вы можете принять ответ, если хотите :-) – Phil

0

Ваша модель ViewModel также не должна быть коллекцией, она должна содержать коллекции и свойства, привязанные к представлению. SelectedRun должен быть собственностью этого ViewModel (MountainViewModel), а не горы. MountainViewModel должен отображать коллекцию Mountains и SelectedRun и должен быть привязан к элементу ItemsSource и SelectedItem списка.

+0

Спасибо! Но это очень простой пример. Описанные мной классы - это очень упрощенные версии ViewModels. Я пробовал решение с привязкой к 'SelectedRun' с использованием свойства' SelectedItem': он ** не помнит последний выбранный пробег внутри категории подъема **. –

+0

Вы имеете в виду, что когда пользователь выбирает другое свойство Mountain или Lift, свойство SelectedRun очищается? – Slugart

+0

@Serge вы могли бы показать нам, как вы привязываетесь к SelectedRun в xaml? – Slugart

2

Вот как я это сделаю. Вы хотите, чтобы вы запускали событие INotifyPropertyChanged при настройке свойств. Чтобы получить выбранный прогон, вам нужно будет получить MainViewModel.SelectedMountain.SelectedLift.SelectedRun.

public class MainViewModel: ViewModelBae 
{ 
    ObservableCollection<MountainViewModel> mountains 
    public ObservableCollection<MountainViewModel> Mountains 
    { 
     get { return mountains; } 
     set 
     { 
      if (mountains != value) 
      { 
       mountains = value; 
       RaisePropertyChanged("Mountains"); 
      } 
     } 
    } 
    MountainViewModel selectedMountain 
    public MountainViewModel SelectedMountain 
    { 
     get { return selectedMountain; } 
     set 
     { 
      if (selectedMountain != value) 
      { 
       selectedMountain = value; 
       RaisePropertyChanged("SelectedMountain"); 
      } 
     } 
    } 
} 

public class MountainViewModel: ViewModelBae 
{ 
    ObservableCollection<LiftViewModel> lifts 
    public ObservableCollection<LiftViewModel> Lifts 
    { 
     get { return lifts; } 
     set 
     { 
      if (lifts != value) 
      { 
       lifts = value; 
       RaisePropertyChanged("Lifts"); 
      } 
     } 
    } 
    LiftViewModel selectedLift 
    public LiftViewModel SelectedLift 
    { 
     get { return selectedLift; } 
     set 
     { 
      if (selectedLift != value) 
      { 
       selectedLift = value; 
       RaisePropertyChanged("SelectedLift"); 
      } 
     } 
    } 
} 

public class LiftViewModel: ViewModelBae 
{ 
    ObservableCollection<string> runs 
    public ObservableCollection<string> Runs 
    { 
     get { return runs; } 
     set 
     { 
      if (runs != value) 
      { 
       runs = value; 
       RaisePropertyChanged("Runs"); 
      } 
     } 
    } 
    string selectedRun 
    public string SelectedRun 
    { 
     get { return selectedLift; } 
     set 
     { 
      if (selectedLift != value) 
      { 
       selectedLift = value; 
       RaisePropertyChanged("SelectedLift"); 
      } 
     } 
    } 
} 

<ListBox ItemsSource="{Binding Mountains}" SelectedItem="{Binding SelectedMountain, Mode=TwoWay}"> 
<ListBox ItemsSource="{Binding SelectedMountain.Lifts}" SelectedItem="{Binding SelectedMountain.SelectedLift, Mode=TwoWay}"> 
<ListBox ItemsSource="{Binding SelectedMountain.SelectedLift.Runs}" SelectedItem="{Binding SelectedMountain.SelectedLift.SelectedRun, Mode=TwoWay}"> 
Смежные вопросы