While trying to find a solution for this problem on browser, bing brought up this content on edge to tell me that there're 3 ways of databinding. Up until now I've always been using the second approach, INotifyPropertyChanged, in viewmodel to update UI and the only solution that works for my problem is reset the DataContext everytime I renew the Property and invoke PropertyChanged in viewmodel
After reading that article I've given it a try with this Model:
class Model : DependencyObject
{
public static readonly DependencyProperty NameProperty, AddressProperty;
static Model() {
NameProperty = DependencyProperty.Register(nameof(Name), typeof(string), typeof(Model), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
AddressProperty = DependencyProperty.Register(nameof(Address), typeof(string), typeof(Model), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
}
public string Name {
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public string Address {
get { return (string)GetValue(AddressProperty); }
set { SetValue(AddressProperty, value); }
}
}
and this Viewmodel:
class Viewmodel : DependencyObject
{
public static readonly DependencyProperty TheModelProperty;
public ObservableCollection<Model> Collection { get; set; }
public ICommand Add { get; set; }
public ICommand Edit { get; set; }
public Viewmodel() {
TheModel = new Model();
Collection = new ObservableCollection<Model>();
BindingOperations.EnableCollectionSynchronization(Collection, Collection);
Add = new Command(add, isValid);
Edit = new Command(edit, (o) => true);
}
static Viewmodel() {
TheModelProperty = DependencyProperty.Register(nameof(TheModel), typeof(Model), typeof(Viewmodel), new PropertyMetadata(null));
}
void add(object o) {
Collection.Add(TheModel);
TheModel = new Model();
}
bool isValid(object o) {
return
!string.IsNullOrEmpty(TheModel.Name) &&
!string.IsNullOrEmpty(TheModel.Address);
}
void edit(object o) {
var model = o as Model;
model.Name = "Edited";
model.Address = "Edited";
}
public Model TheModel {
get { return (Model)GetValue(TheModelProperty); }
set { SetValue(TheModelProperty, value); }
}
}
for this UI in MainWindow.xaml:
<Window.DataContext>
<VM:Viewmodel/>
</Window.DataContext>
<Grid Margin="20" x:Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding TheModel.Name, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Row="1" Text="{Binding TheModel.Address, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Row="2" Content="Add" Command="{Binding Add}"/>
<ListBox Grid.Row="3" Name="lb" ItemsSource="{Binding Collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Address}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Grid.Row="4" Content="Edit" Command="{Binding Edit}" CommandParameter="{Binding ElementName=lb, Path=SelectedItem}"/>
</Grid>
and, interestingly, everything works as expected:

in my existing project, in some places, I access and modify model/viewmodel properties on different thread so I wanted to do the same with the following modified add and edit methods of my Viewmodel:
void add(object o) {
Task.Run(() => {
Collection.Add(TheModel);
TheModel = new Model();
});
}
void edit(object o) {
var model = o as Model;
Task.Run(() => {
model.Name = "Edited";
model.Address = "Edited";
});
}
BUT it doesn't work! Is it possible to do that somehow?