Please can you advise if this is possible or what approach is best?
I will add my code afterwards but I am worried that it will add limited value to what I am trying to ask/explain.
The WPF examples that I have seen implement
- A (poco) model e.g Customer.
- Then they implement a view model (MVVM pattern). (The View Model needs to implement ObservableCollection and or implement INotifyPropertyChanged interface so that any changes in the model are reflected in the UI once the model changes.)
- In the xaml code behind, in the page constructor, the ViewModel is passed to the DataContext.
- The xaml can then bind to this View Model Data with a Mode of update e.g. TwoWay.
Here is what I need to understand. I have implemented my own data model / class, which has async tasks constantly updating the status of different fields in this class.
My model resides in a separate class library that I would like to inject/supply it to a view model. However, since my object/class is 'self-updating', I can't simply copy across values into my view model - since they will change over time. I want my view model to be aware of changes that underlying values and show these changes in the UI as the async tasks update the model.
How do I go about this? So in my example, my Customer object will be self-updating, some background task would add/remove customers in a class library outside of my ViewModel.
I hope that I have managed to ask my question in a way that is clear to understand.
The XAML binding to the Customer View Model
<ListView Grid.Row="1" ItemsSource="{x:Bind ViewModel.Customers,Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedCustomer,Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Customer">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind FirstName,Mode=OneWay}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind LastName,Mode=OneWay}"
Margin="5 0 0 0"/>
<TextBlock Text="(Developer)" Margin="5 0 0 0" Opacity="0.5"
Visibility="{x:Bind IsDeveloper,Mode=OneWay}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Reference for this sample code
public class MainViewModel : Observable
{
private ICustomerDataProvider _customerDataProvider;
private Customer _selectedCustomer;
public MainViewModel(ICustomerDataProvider customerDataProvider)
{
_customerDataProvider = customerDataProvider;
Customers = new ObservableCollection<Customer>();
}
public Customer SelectedCustomer
{
get { return _selectedCustomer; }
set
{
if (_selectedCustomer != value)
{
_selectedCustomer = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsCustomerSelected));
}
}
}
public bool IsCustomerSelected => SelectedCustomer != null;
public ObservableCollection<Customer> Customers { get; }
public async Task LoadAsync()
{
Customers.Clear();
var customers = await _customerDataProvider.LoadCustomersAsync();
foreach (var customer in customers)
{
Customers.Add(customer);
}
}
public async Task SaveAsync()
{
await _customerDataProvider.SaveCustomersAsync(Customers);
}
public void AddCustomer()
{
var customer = new Customer { FirstName = "New" };
Customers.Add(customer);
SelectedCustomer = customer;
}
public void DeleteCustomer()
{
var customer = SelectedCustomer;
if (customer != null)
{
Customers.Remove(customer);
SelectedCustomer = null;
}
}
}
The INotifyPropertyChanged is implemented here:
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}