سؤال

I read a couple of MVVM Tutorials (1,2,3,4) but I can't find a proper answer to my problem.

My model is a hierarchical tree like this:

public class MyModel {
    public string Name { get; set; }
    public Guid Id { get; set; }
    public List<MyModel> Children { get; set; }
}

Now I want to display this in a TreeView like this (each entry if from the type MyModel):

Root
|-SubElement
|-SubElement2
|  |-SubSubElement1
|-SubElement3

Now my questions:

  • How would the corresponding View-Model look like? Is there a reference implementation for Collections?
  • Should the Model or the View-Model or both implement INotifyPropertyChanged, INotifyCollectionChanged or should the List of Children be of the Type ObservableCollection<MyModel>? If so, when to call OnPropertyChanged()?

Now for the displaying:

I would like to display the Name of the object in the TreeView, but when selecting the element, I want to be notified of that event (and get the corresponding element). The ViewModel must somehow support this. Something like holding a list (say MyModelList) to which I can bind in XAML, like:

<TreeView ...
   ItemsSource="{Binding ElementName=MyModelList, Path=SelectedItem.Name}"

... >

and where I can use InputBindings or EventTriggers.

هل كانت مفيدة؟

المحلول

Try using Hierarchical data template for showing tree structure within TreeView

<Grid>
    <Grid.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}" 
                                  DataType="{x:Type local:MyModel}">
            <TextBlock Text="{Binding Name}" />
        </HierarchicalDataTemplate>
    </Grid .Resources>
    <TreeView ItemsSource="{Binding MyModelList}"/>
</Grid>

Go through this MSDN Blog to get a better understanding - TreeView and HierarchicalDataTemplate, Step-by-Step

نصائح أخرى

How would the corresponding View-Model look like?

In this situation will be Model and the collection, which will be in the ViewModel.


Should the Model or the View-Model or both implement INotifyPropertyChanged

I advise you to use ObservableCollection<T>, because all changes for Collection will automatically (add, remove, etc) appear in it. Properties that will be in Model must implement INotifyPropertyChanged interface. I personally do it on the side of the Model, but there are opponents of this idea, so where to implement it - your personal desire.

Example of this idea:

Model

public class MyModel : NotificationObject // he implement INotifyPropertyChanged 
{
   ...
}

ViewModel

public ObservableCollection<MyModel> MyObjects 
{
    get;
    set;
}

// in Constructor of ViewModel
MyLogObjects = new ObservableCollection<MyModel>();

When selecting the element, I want to be notified of that event

In WPF and Silverlight TreeView.SelectedItem is a readonly property. In this case you can see this example:

<StackPanel x:Name="LayoutRoot"> 
    <StackPanel.Resources> 
        <sdk:HierarchicalDataTemplate x:Key="ChildTemplate" ItemsSource="{Binding Path=Children}" > 
            <TextBlock Text="{Binding Path=Name}" /> 
        </sdk:HierarchicalDataTemplate> 

        <sdk:HierarchicalDataTemplate x:Key="NameTemplate" 
                                      ItemsSource="{Binding Path=Children}" 
                                      ItemTemplate="{StaticResource ChildTemplate}">
            <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" /> 
        </sdk:HierarchicalDataTemplate> 
    </StackPanel.Resources> 

    <sdk:TreeView x:Name="myTreeView"
                  Width="400"  
                  Height="300" 
                  ItemsSource="{Binding HierarchicalAreas}" 
                  ItemTemplate="{StaticResource NameTemplate}"
                  local:Attached.TreeViewSelectedItem="{Binding SelectedArea, Mode=TwoWay}" /> 
</StackPanel> 

Prefix sdk: needed for Silverlight

For notified event you can create an PropertyChangedEventHandler event handler for ViewModel in constructor, to know that the SelectedItem changed:

public MyViewModel() 
{
    MyModel = new MyModel();        
    MyModel.PropertyChanged += new PropertyChangedEventHandler(MyModel_PropertyChanged);
}

private void MyModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName.Equals("SelectedItem")) 
    {
        System.Diagnostics.Debug.WriteLine("SelectedItem changed");
    }            
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top