Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM treeview wpf(binding?)

Sorry for noob question. Perhaps this is not a question - but I need a tutorial sample/ I am trying to write a model task to get "handy" with mvvm pattern in wpf. I am decide to write something like librarian helper. That is one simple wpf window with one combobox(for selecting if the book is fantasy or sf), textbox (for book name input), button Add, and a treeview with a tree like:

 Books
  ------>ScienceFic
        ----->bookName1
        ----->bookName2
  ------->Fantasy
        ------>bookName3

And I have some difficulties with binding and separation view model from view. Could You help me?

public enum LibraryType
{
    ScienceFic,
    Fantasy
}
    Class Model: INotifyPropertyChanged
    {
     private int bookId;
     private string bookName;
     private LibraryType bookType;
     public event PropertyChangedEventHandler PropertyChanged;
        //....and for all this fields  I have used a INotifyPropertyChanged as 
    /*
    http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist
    */
    }

At this point the MODEL is finished I think.

Now about VIEW: I have simply open editor of MainWindow and manually added button, textbox, combobox, and a treeview. After addition of

comboBox1.ItemsSource = Enum.GetValues(typeof(LibraryType)).Cast<LibraryType>();
 comboBox1.SelectedIndex = 0;

I have initialized my combo with right types of books))) But((, I have done this in code, not in XAML - is this right for MVVM Binding? (first question) Next, I have bind (as I suppose) my textBox text to current book name property in ViewModel (I have done this in XAML like this):

 <TextBox Text="{Binding Path=CurrentBookName}"/>

is this right? (second question)

And, finally, VIEWMODEL

 Class ViewModel
{
  private string currentBookName;
  private LibraryType selectedBookType;
  public event PropertyChangedEventHandler PropertyChanged;
  //also properties and  OnPropertyChanged/SetField functions like in Model class

  //and finally I have created two lists for book storing
  private List<Model> sfStorage = new List<Model>();
  private List<Model> fantasyStorage = new List<Model>();
  //and simple getters for this two lists, like:
  public List<Model> GetSFStorage
  {
   get{return this.sfStorage;}
  }
  //and a simple function for addition of new books
  //that I plan to call when AddButton pressed
  public void Addition(???)
        {
            if (!string.IsNullOrEmpty(currentBookName))
            {
                //? I have add CurrentBookName in XAML of View (see above)
                //?but is it enough to have a property of CurrentBookType
                //to grant that a valide value from combobox will be here?
                var modelNewBook = new Model(CurrentBookName,CurrentBookType);
                switch (selectedBookType)
                {
                    case LibraryType.ScienceFic:
                        sfStorage.Add(modelNewBook);
                        break;
                    case LibraryType.Fantasy:
                        fantasyStorage.Add(modelNewBook);
                        break;
                    default:
                        return;
                }
            }
}

Now I am only few step out of success (may be) BUT, how I could connect a treeView with this two lists in xaml or in code And how could I call Addition function when an Addbutton pressed (third and main question)? Perhaps, this is noob question, but I really need an sample. And, (perhaps) this question will be helpfull for others who try to understand MVVM and binding.

like image 682
curiousity Avatar asked Jan 23 '14 15:01

curiousity


2 Answers

The following code is a quick hack of your application. I also understood that you have problems with the treeview so i only display the code passanges to the treeview and i fill my books list inside the constructor of my view model to have some data

Model:

internal class Book : NotifyPropertyChangedBase
{
    private string name;
    private BookType type;
    public BookType Type
    {
       get => this.type;
    }
    set
    {
        this.SetProperty( ref this.type,value );
    }
}

public string Name
{
    get => return this.name;
    set
    {
        this.SetProperty( ref this.name,value );
    }
}

ViewModel:

private readonly List<Book> books;

public MainViewModel( )
{
    this.books = new List<Book>
    {
        new Book
        {
            Name = "Book 1",
            Type = BookType.Fantasy
        },
        new Book
        {
            Name = "Book 2",
            Type = BookType.Fantasy
        },
        new Book
        {
            Name = "Book 3",
            Type = BookType.Fantasy
        },
        new Book
        {
            Name = "Book 4",
            Type = BookType.SciFi
        }
    };
}

public ICollectionView Books
{
    get
    {
        var source = CollectionViewSource.GetDefaultView( this.books );
        source.GroupDescriptions.Add( new PropertyGroupDescription( "Type" ) 
    );
    return source;
}

View:

<TreeView ItemsSource="{Binding Books.Groups}">
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Items}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>
</TreeView>
like image 118
Sukram Avatar answered Sep 30 '22 23:09

Sukram


From what I understand you need help generating the hierarchy in TreeView using a ViewModel. Todo this you will be using a HierarchicalDataTemplate. Your ViewModel will require a collection of children, and you will use the simply bind the ItemsSource property of the HierarchicalDataTemplate to that collection.

Take a look at this simple example someone made: TreeView and HierarchicalDataTemplate, Step-by-Step

like image 42
deloreyk Avatar answered Oct 01 '22 00:10

deloreyk