Going through:
WPF binding not updating the view https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged?redirectedfrom=MSDN&view=netcore-3.1
and
WPF DataContext updated but UI not updated
I still can't see why the UI is not updating in the following case (my best guess is that the DataContext of the Grid to be updated is not updated) and am loosing my mind:
AppliedJobsModel.cs (has IPropertyChange implemented as some of the answers suggest):
public class AppliedJobsModel { }
public class AppliedJob : INotifyPropertyChanged
{
private string appliedDate;
private string url;
private string company;
private string description;
private string contact;
private string stack;
private string response;
private string interviewDate;
public AppliedJob(string[] entries)
{
appliedDate = entries[Consts.APPLIED_DATE_INDEX];
url = entries[Consts.URL_INDEX];
company = entries[Consts.COMPANY_INDEX];
description = entries[Consts.DESCRIPTION_INDEX];
contact = entries[Consts.CONTACT_INDEX];
stack = entries[Consts.STACK_INDEX];
response = entries[Consts.RESPONSE_INDEX];
interviewDate = entries[Consts.INTERVIEWDATE_INDEX];
}
public string AppliedDate
{
get {
return appliedDate;
}
set {
if (appliedDate != value)
{
appliedDate = value;
RaisePropertyChanged("AppliedDate");
}
}
}
public string Url
{
get
{
return url;
}
set
{
if (url != value)
{
url = value;
RaisePropertyChanged("Url");
}
}
}
public string Company
{
get
{
return company;
}
set
{
if (company != value)
{
company = value;
RaisePropertyChanged("Company");
}
}
}
public string Description
{
get
{
return description;
}
set
{
if (description != value)
{
description = value;
RaisePropertyChanged("Description");
}
}
}
public string Contact
{
get
{
return contact;
}
set
{
if (contact != value)
{
contact = value;
RaisePropertyChanged("Contact");
}
}
}
public string Stack
{
get
{
return stack;
}
set
{
if (stack != value)
{
stack = value;
RaisePropertyChanged("Stack");
}
}
}
public string Response
{
get
{
return response;
}
set
{
if (response != value)
{
response = value;
RaisePropertyChanged("Response");
}
}
}
public string InterviewDate
{
get
{
return interviewDate;
}
set
{
if (interviewDate != value)
{
interviewDate = value;
RaisePropertyChanged("InterviewDate");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
AppliedJobsViewModel.cs (has an observable collection that gets correctly updated when a button is clicked (in dbg)):
class AppliedJobsViewModel
{
private TexParser texParser;
public AppliedJobsViewModel() {
// TODO:
// -- do nothing here
}
public ObservableCollection<AppliedJob> AppliedJobsCollection
{
get;
set;
}
private ICommand _openTexClick;
public ICommand OpenTexClick
{
get
{
return _openTexClick ?? (_openTexClick = new CommandHandler(() => ReadAndParseTexFile(), () => CanExecute));
}
}
public bool CanExecute
{
get
{
// check if executing is allowed, i.e., validate, check if a process is running, etc.
return true;
}
}
public async Task ReadAndParseTexFile()
{
if (texParser == null)
{
texParser = new TexParser();
}
// Read file asynchronously here
await Task.Run(() => ReadFileAndUpdateUI());
}
private void ReadFileAndUpdateUI()
{
texParser.ReadTexFile();
string[][] appliedJobsArray = texParser.getCleanTable();
// Use this:
// https://rachel53461.wordpress.com/2011/09/17/wpf-grids-rowcolumn-count-properties/
// Update collection here
List<AppliedJob> appliedJobsList = createAppliedJobsListFromTable(appliedJobsArray);
AppliedJobsCollection = new ObservableCollection<AppliedJob>(appliedJobsList);
}
private List<AppliedJob> createAppliedJobsListFromTable(string[][] table)
{
List<AppliedJob> jobsList = new List<AppliedJob>();
for (int i = 0; i < table.Length; i++)
{
jobsList.Add(new AppliedJob(table[i]));
}
return jobsList;
}
}
AppliedJobsView.xaml:
<UserControl x:Class="JobTracker.Views.AppliedJobsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:JobTracker.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Name="appliedJobsGrid" Grid.Row="1" Grid.Column="1" Background="#50000000" Margin="10,10,10,10">
<ItemsControl ItemsSource = "{Binding Path = AppliedJobsCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = AppliedDate, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = Url, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = Company, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = Description, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = Contact, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = Stack, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = Response, Mode = TwoWay}" Width = "100" />
<TextBox Text = "{Binding Path = InterviewDate, Mode = TwoWay}" Width = "100" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
TrackerHome.xaml (main page/uses the user control):
<Grid Grid.Row="1" Grid.Column="1">
<views:AppliedJobsView x:Name = "AppliedJobsControl" Loaded = "AppliedJobsViewControl_Loaded" />
</Grid>
TrackerHome.cs:
public TrackerHome()
{
InitializeComponent();
// Set data context here (https://stackoverflow.com/questions/12422945/how-to-bind-wpf-button-to-a-command-in-viewmodelbase)
// https://stackoverflow.com/questions/33929513/populate-a-datagrid-using-viewmodel-via-a-database
if (appliedJobsViewModel == null)
{
appliedJobsViewModel = new AppliedJobsViewModel();
}
this.DataContext = appliedJobsViewModel;
//AppliedJobControl.DataContext = appliedJobsViewModel;
}
private void AppliedJobsViewControl_Loaded(object sender, RoutedEventArgs e)
{
if (appliedJobsViewModel == null)
{
appliedJobsViewModel = new AppliedJobsViewModel();
}
AppliedJobsControl.DataContext = appliedJobsViewModel;
}