C
C#2mo ago
HFrederick

✅ How to bind an object observable property with mvvm community toolkit in wpf

I'm trying to migrate a wpf app to use the mvvm toolkit. I have a viewmodel and model setup that looks like this:
public partial class MyViewmodel : ObservableObject
{
[ObservableProperty]
private Book? book;

[RelayCommand]
public void LoadBook()
{
Book = FileLoaderService.Load("filepathhere.zip");
}

[RelayCommand]
public void AddChapter()
{
Book.Chapters.Add(new Chapter("New chapter", "new content"));
}
[RelayCommand]
public void ChangeTitle()
{
Book.Title = "New title";
}
}

public class Book
{
public string Title {get;set;}
public List<Chapter> Chapters {get;};
}

public class Chapter
{
public string ChapterTitle {get;}
public string Content {get;}
}
public partial class MyViewmodel : ObservableObject
{
[ObservableProperty]
private Book? book;

[RelayCommand]
public void LoadBook()
{
Book = FileLoaderService.Load("filepathhere.zip");
}

[RelayCommand]
public void AddChapter()
{
Book.Chapters.Add(new Chapter("New chapter", "new content"));
}
[RelayCommand]
public void ChangeTitle()
{
Book.Title = "New title";
}
}

public class Book
{
public string Title {get;set;}
public List<Chapter> Chapters {get;};
}

public class Chapter
{
public string ChapterTitle {get;}
public string Content {get;}
}
Now if I try to update a property of "Book" like in ChangeTitle or AddChapter methods, the view doesn't update. I guess ObservableProperty only works when assigning a new value directly to the tagged property. Because my LoadBook method can definitely update the view. I'm binding my view like this:
<TextBlock Content="{Binding Book.Title}" />
<ListBox ItemsSource={Binding Book.Chapters}>
<TextBlock Content="{Binding ChapterTitle}" />
<TextBlock Content="{Binding Content}" />
</ListBox>
<TextBlock Content="{Binding Book.Title}" />
<ListBox ItemsSource={Binding Book.Chapters}>
<TextBlock Content="{Binding ChapterTitle}" />
<TextBlock Content="{Binding Content}" />
</ListBox>
How can I make it so that updating the inner properties of Book also updates the Book property itself? Or maybe I shouldn't use the Book object directly and I should just expose the Book properties directly in the viewmodel like this below?
public partial class MyViewmodel : ObservableObject
{
[ObservableProperty]
private string title;

[ObservableProperty]
private ObservableCollection<Chapter> chapters;

// ...
}
public partial class MyViewmodel : ObservableObject
{
[ObservableProperty]
private string title;

[ObservableProperty]
private ObservableCollection<Chapter> chapters;

// ...
}
4 Replies
leowest
leowest2mo ago
For what u want u would have to implement observability over book and chapter as well, so that updating the properties via code will reflect on the UI. Do not mix model(entities efcore), dtos and viewmodels, specially in WPF as using dtos directly to represent viewmodels in WPF can cause memory leak and other side effects u want to avoid.
public partial class MyViewModel : BaseViewModel
{
[ObservableProperty]
private BookViewModel? book;

[RelayCommand]
public void LoadBook()
{
Book = FileLoaderService.Load("filepathhere.zip");
}

[RelayCommand]
public void AddChapter()
{
Book.Chapters.Add(new Chapter("New chapter", "new content"));
}
[RelayCommand]
public void ChangeTitle()
{
Book.Title = "New title";
}
}

public partial class BookViewModel : BaseViewModel
{
[ObservableProperty]
private string title;
[ObservableProperty]
private ObservableCollection<ChapterViewModel> chapters;
}

public partial class ChapterViewModel : BaseViewModel
{
[ObservableProperty]
private string chapterTitle;
[ObservableProperty]
private string content;
}

public partial class BaseViewModel : ObservableObject;
public partial class MyViewModel : BaseViewModel
{
[ObservableProperty]
private BookViewModel? book;

[RelayCommand]
public void LoadBook()
{
Book = FileLoaderService.Load("filepathhere.zip");
}

[RelayCommand]
public void AddChapter()
{
Book.Chapters.Add(new Chapter("New chapter", "new content"));
}
[RelayCommand]
public void ChangeTitle()
{
Book.Title = "New title";
}
}

public partial class BookViewModel : BaseViewModel
{
[ObservableProperty]
private string title;
[ObservableProperty]
private ObservableCollection<ChapterViewModel> chapters;
}

public partial class ChapterViewModel : BaseViewModel
{
[ObservableProperty]
private string chapterTitle;
[ObservableProperty]
private string content;
}

public partial class BaseViewModel : ObservableObject;
The idea in WPF is that u will create viewmodels to represent your view, it doesnt necessarily mean that it will be just a single viewmodel it can have child vms inside of it as well representing further down controls, lists and such.
HFrederick
HFrederickOP2mo ago
Oh I see, I can tag the models directly :ThonkAnime: And yeah, this Book object is used within the wpf app only. By the time I get a book object from the service's Load() method, it's nothing more than an object wrapping around some copies of strings, lists, and ints.
leowest
leowest2mo ago
I would still call it a viewmodel to uniform what its representing as it could potentially have more stuff later down the road but yes essentially u need to do that
MODiX
MODiX2mo ago
If you have no further questions, please use /close to mark the forum thread as answered

Did you find this page helpful?