I copied this code from another project and can't figure out why it isn't working. My observable collections are working great binding and updating, but my textboxes aren't changing. I have a button click that lets the user pick a directory (DirectoryBrowse() method) and then assigns that value to the data context's property that is bound to the textbox. PropertyChanged is always null and I can't figure out why! The initial binding works just fine, just note when I change the value in the code-behind. I've been at this entirely too long, but any help would be appreciated!
DataContext class:
[Serializable]
public class Settings : ViewModels.ViewModelEntity
{
public static Settings defaultSettings { get; set; }
private string _ExportDir;
public string ExportDir
{
get { return this._ExportDir; }
set
{
if (this._ExportDir != value)
{
this._ExportDir = value;
this.NotifyPropertyChanged("ExportDir");
}
}
}
private string _LastRunTime;
public string LastRunTime
{
get { return this._LastRunTime; }
set
{
if (this._LastRunTime != value)
{
this._LastRunTime = value;
this.NotifyPropertyChanged("LastRunTime");
}
}
}
private string _TSCertPath;
public string TSCertPath
{
get { return this._TSCertPath; }
set
{
if (this._TSCertPath != value)
{
this._TSCertPath = value;
this.NotifyPropertyChanged("TSCertPath");
}
}
}
public ObservableCollection<Map> Brokers { get; set; }
public ObservableCollection<Account> Accounts { get; set; }
public List<Holiday> Holidays { get; set; }
public bool RefreshHolidays { get; set; }
public string ProxyServer { get; set; }
public string ProxyPort { get; set; }
public string ProxyUsername { get; set; }
public string ProxyPassword { get; set; }
public bool TSProd { get; set; }
public string TSTriad { get; set; }
public string TSPassword { get; set; }
public string TSCertPassword { get; set; }
public Settings()
{
this.Brokers = new ObservableCollection<Map>();
this.Accounts = new ObservableCollection<Account>();
}
}
Xaml:
<TextBlock TextWrapping="Wrap" Text="File Export Path*"/>
<TextBox TextWrapping="Wrap" Text="{Binding Path=ExportDir, Mode=TwoWay}" />
<Button x:Name="btnBrowseExportDir" Content="..." Click="btnBrowseExportDir_Click"/>
Code-behind:
public MainWindow()
{
InitializeComponent();
Settings.Initialize();
this.DataContext = Settings.defaultSettings;
string[] args = Environment.GetCommandLineArgs();
if (args.Contains("create"))
{
this.Close();
}
}
private string DirectoryBrowse()
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
if (result.ToString().ToUpper() == "OK")
{
if (!Directory.Exists(dialog.FileNames.First()))
{
this.lblStatus.Text = "Invalid directory selected";
return string.Empty;
}
else
{
return dialog.FileNames.First();
}
}
else
{
this.lblStatus.Text = "Invalid directory selected";
return string.Empty;
}
}
private void btnBrowseExportDir_Click(object sender, RoutedEventArgs e)
{
Settings.defaultSettings.ExportDir = DirectoryBrowse();
}
ViewModelEntity:
public class ViewModelEntity
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Settings.defaultSettings is never assigned a value. So the databinding have nothing to work with.
Thoug code for Settings.Initialize() is missing.
#Dave and #Icepickle showed me what I was missing, no implementaiton of INotifyPropertyChanged!
Related
I have the following code that retrieves json from an api. This works because when I put a breakpoint on it, it neatly shows the json from the url.
The json looks like this when I put a breakpoint on it
And the code of getting the json from the url looks like this
public static List GetAllSpecTypes(string acces_Token, string domain, out bool result)
{
result = true;
var specTypes = new List<Specification>();
if (!string.IsNullOrEmpty(domain))
{
try
{
using (HttpClient client = new HttpClient())
{
string url = $"{domain}/api/specification/GetSpecificationType";
client.BaseAddress = new Uri(url);
MediaTypeWithQualityHeaderValue contentType = new MediaTypeWithQualityHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Add("cache-control", "no-cache");
client.DefaultRequestHeaders.Add("Authorization", acces_Token);
HttpResponseMessage response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
string json = response.Content.ReadAsStringAsync().Result;
specTypes = JsonSerializer.Deserialize<List<Specification>>(json);
}
else
{
result = false;
}
}
}
catch (Exception)
{
//log!
}
}
return specTypes;
}
And the json from the breakpoint is this:
"[{\"SpecificationTypeId\":1,\"SpecificationTypeName\":\"Overig\"},{\"SpecificationTypeId\":2,\"SpecificationTypeName\":\"Eten/Drinken\"},{\"SpecificationTypeId\":3,\"SpecificationTypeName\":\"Parkeren\"},{\"SpecificationTypeId\":4,\"SpecificationTypeName\":\"Ander vervoer\"},{\"SpecificationTypeId\":5,\"SpecificationTypeName\":\"Materiaal\"},{\"SpecificationTypeId\":6,\"SpecificationTypeName\":\"Persoonlijke uitgaven\"},{\"SpecificationTypeId\":7,\"SpecificationTypeName\":\"Uitgaven cliƫnt\"},{\"SpecificationTypeId\":8,\"SpecificationTypeName\":\"Overnachting\"},{\"SpecificationTypeId\":9,\"SpecificationTypeName\":\"Congres / beursbezoek\"},{\"SpecificationTypeId\":10,\"SpecificationTypeName\":\"Brandstof\"},{\"SpecificationTypeId\":11,\"SpecificationTypeName\":\"Auto kosten\"},{\"SpecificationTypeId\":12,\"SpecificationTypeName\":\"Eigen vervoer\"},{\"SpecificationTypeId\":14,\"SpecificationTypeName\":\"Vervoer\"}]"
This method should return the specTypes to a viewmodel. But when I do, it's empty when I put a breakpoint on it.
That code is as follows
public ViewModel()
{
this.Source = new List<SourceItem>();
var data = Api.GetAllSpecTypes(Settings.AccessToken, Settings.Domain, out var valid);
foreach (var item in data)
{
Source.Add(new SourceItem(item.SpecificationName, item.SpecificationId));
}
}
What I want to achieve is that here that json is returned from the api call so that I can bind it to a label in a listview.
The listview xaml looks like this in which I put in the label where I use the following:
<Label
FontSize="18"
LineBreakMode="NoWrap"
Text="{Binding Name}"
TextColor="#474747"
VerticalOptions="FillAndExpand" />
What should be in the label are the specificationnames coming from the json
How can i achieve this?
This is my entire viewmodel according to my question
public class SourceItem : INotifyPropertyChanged
{
public SourceItem(string name, int id)
{
this.Name = name;
this.Id = id;
}
private string name;
public string Name
{
get { return this.name; }
set
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
private int id;
public int Id
{
get { return this.id; }
set
{
this.id = value;
this.OnPropertyChanged("Id");
}
}
private bool isSelected;
public bool IsSelected
{
get { return this.isSelected; }
set
{
this.isSelected = value;
this.OnPropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
public class ViewModel : INotifyPropertyChanged
{
private bool _isSelected = false;
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public ViewModel()
{
this.Source = new List<SourceItem>();
var data = Api.GetAllSpecTypes(Settings.AccessToken, Settings.Domain, out var valid);
foreach (var item in data)
{
Source.Add(new SourceItem(item.SpecificationName, item.SpecificationId));
}
}
public List<SourceItem> Source { get; set; }
}
And the Specification Class for the JSON is the following:
public class Specification
{
public int SpecificationId { get; set; }
public string SpecificationName { get; set; }
public string SpecificationDescription { get; set; }
}
How do I get the specification names from the json in the xaml label based on my question?
thanks in advance
your json looks like
"[{\"SpecificationTypeId\":1,\"SpecificationTypeName\"
while your C# classes do not include the "Type" in the name
public class Specification
{
public int SpecificationId { get; set; }
public string SpecificationName { get; set; }
public string SpecificationDescription { get; set; }
}
you either need to rename your C# properties to match the json, or use an attribute to map the name
[JsonProperty("SpecificationTypeId")]
public int SpecificationId { get; set; }
so I have a model class that I called "Objets" and I want to creat a ViewModel so that I can track the changes that happen in one of my Model class arguments which is "nbr_objet".
what should I do ?
this what I've done so far and please correct me.
Model Class :
public class Objets
{
public string Designation { get; set; }
public string Description { get; set; }
public float Prix { get; set; }
public int nbr_objet { get; set; }
public Objets(string Designation, string Description, float Prix, int nbr_objet)
{
this.Designation = Designation;
this.Description = Description;
this.Prix = Prix;
this.nbr_objet= nbr_objet;
}
}
ModelViewBase where I have the problem obviously
class ViewModelBase : INotifyPropertyChanged
{
public Objets ObjetVM { get; set; }
public int nbr_objet
{
get { return ObjetVM.nbr_objet; }
set
{
ObjetVM.nbr_objet = value;
OnPropertyChanged(nameof(ObjetVM.nbr_objet));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
And this is my MainPage.xaml.cs where I creat multiple "Objets"
public MenuPage()
{
InitializeComponent();
this.BindingContext = new ViewModelBase();
}
Here is running screenshot.
You can achieve it like following format in your model.
public class MyObjets : INotifyPropertyChanged
{
// public string Designation { get; set; }
// public string Description { get; set; }
// public float Prix { get; set; }
// public int nbr_objet { get; set; }
int _nbr_objet;
public int Nbr_objet
{
get
{
return _nbr_objet;
}
set
{
if (_nbr_objet != value)
{
_nbr_objet = value;
OnPropertyChanged("Nbr_objet");
}
}
}
float _prix;
public float Prix
{
get
{
return _prix;
}
set
{
if (_prix != value)
{
_prix = value;
OnPropertyChanged("Prix");
}
}
}
string _designation;
public string Designation
{
get
{
return _designation;
}
set
{
if (_designation != value)
{
_designation = value;
OnPropertyChanged("Designation");
}
}
}
string _description;
public string Description
{
get
{
return _description;
}
set
{
if (_description != value)
{
_description = value;
OnPropertyChanged("Description");
}
}
}
public MyObjets(string Designation, string Description, float Prix, int nbr_objet)
{
this._designation = Designation;
this._description = Description;
this._prix = Prix;
this._nbr_objet = nbr_objet;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then Here is Layout.
<StackLayout>
<!-- Place new controls here -->
<Label Text="{Binding Designation}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Label Text="{Binding Description}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Label Text="{Binding Prix}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Label Text="{Binding Nbr_objet}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
Here is layout backend code.
public MainPage()
{
InitializeComponent();
BindingContext = new MyObjets("xxxx","cccc",1.22f,11);
}
Here is my demo about MVVM with Listview, you can refer to it as well.
https://github.com/851265601/MVVMListview
If the reply is helpful, please do not forget to mark it as answer.
======================Update========================
You want to achieve the result like following GIF?
Here is your model
public class MyObjets
{
public string Designation { get; set; }
public string Description { get; set; }
public float Prix { get; set; }
public int nbr_objet { get; set; }
public MyObjets(string Designation, string Description, float Prix, int nbr_objet)
{
this.Designation = Designation;
this.Description = Description;
this.Prix = Prix;
this.nbr_objet = nbr_objet;
}
}
Here is ViewModelBase
public class ViewModelBase: INotifyPropertyChanged
{
public ViewModelBase()
{
ObjetVM = new MyObjets("ccc","xxx",1.2f,123);
}
public MyObjets ObjetVM { get; set; }
public int nbr_objet
{
get { return ObjetVM.nbr_objet; }
set
{
ObjetVM.nbr_objet = value;
OnPropertyChanged(nameof(ObjetVM.nbr_objet));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
Here layout forground code.
<StackLayout>
<Label Text="{Binding nbr_objet}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="change the value" Clicked="Button_Clicked"></Button>
</StackLayout>
here is layout background code.
public partial class MainPage : ContentPage
{
ViewModelBase viewModelBase;
public MainPage()
{
InitializeComponent();
viewModelBase = new ViewModelBase();
BindingContext = viewModelBase;
}
private void Button_Clicked(object sender, EventArgs e)
{
viewModelBase.nbr_objet = 111;
}
}
You need to implement INotifyPropertyChanged on any object you want to track changes on. Right now you are only tracking changes on the viewmodel, so you also need to add INotifyPropertyChanged on the Objets class, too, as well as each property within the class with the getters/setters with OnPropertyChanged like you did in the viewmodel.
public class Objets: INotifyPropertyChanged
When you change the property "nbr_objet" you raise that your property inside the ObjetVM has changed, but this is not your bindingContext - your bindingContext is the ViewModelBase.
So rather rewrite it:
private int nbr_object;
public int Nbr_objet_property
{
get { return nbr_objet; }
set
{
nbr_objet = value;
OnPropertyChanged(nameof(Nbr_objet_property));
}
}
And then everytime you cahnge "Nbr_objet_property" it should update whatever you binded it to.
Also, "ObjetVM" is no a viewModel since it does not implement the INotifyPropertyChanged logic.
Hope it makes sense? :)
I need to display and set an exchange rate in a textbox.
My ViewModel contains a decimal property named ExchangeRate. By default it's only possible to enter up to two decimal places.
Exchange rates usually contains more then two decimal places so I tried to achieve this with StringFormat:
<TextBox HorizontalAlignment="Left"
IsEnabled="{Binding ExchangeRateNeeded}"
Text="{Binding ExchangeRate, UpdateSourceTrigger=PropertyChanged, Delay=250, Mode=TwoWay, StringFormat={}{0:0.00000}}"
Height="23" Margin="130,92,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="80" MaxLength="4"/>
It displays great, but I am not able to enter a value with this formatting option.
How can I enter more then 2 decimal places?
ViewModel:
public class SetupWindowViewModel : ViewModelBase
{
public ObservableCollection<SapVkorg> SapVkOrgs { get; }
public SapVkorg SelectedVkOrg { get; set; }
public ICommand OkCommand { get; }
public int Year { get; set; }
public bool ApertumNumbers { get; set; }
public ObservableCollection<Currency> Currencies { get; }
public Currency SelectedCurrency { get; set; }
public decimal ExchangeRate { get; set; }
public bool ExchangeRateNeeded { get { return SelectedCurrency != Currency.EUR; } }
public SetupWindowViewModel(Window window) : base(window)
{
OkCommand = new RelayCommand(Save, CanSave);
SapVkOrgs = mainController.GetSapVkorgs();
Currencies = mainController.GetCurrencies();
SelectedVkOrg = SettingsHolder.SapVkorg;
Year = SettingsHolder.Year;
ApertumNumbers = SettingsHolder.ApertumNumbers;
ExchangeRate = SettingsHolder.ExchangeRate;
SelectedCurrency = SettingsHolder.Currency;
}
public void Save()
{
SettingsHolder.SapVkorg = SelectedVkOrg;
SettingsHolder.Year = Year;
SettingsHolder.Currency = SelectedCurrency;
SettingsHolder.ExchangeRate = ExchangeRate;
SettingsHolder.ApertumNumbers = ApertumNumbers;
CloseWindow();
}
public bool CanSave()
{
return Year > 0 &&
SelectedVkOrg != null &&
((ExchangeRateNeeded && ExchangeRate != 1) || (!ExchangeRateNeeded));
}
}
ViewModelBase:
[AddINotifyPropertyChangedInterface]
public abstract class ViewModelBase
{
protected readonly MainController mainController;
protected static readonly log4net.ILog log = LogHelper.GetLogger();
protected readonly Window window;
public ICommand CloseWindowCommand { get; }
protected ViewModelBase(Window window)
{
mainController = MainController.GetInstance();
this.window = window;
CloseWindowCommand = new RelayCommand(CloseWindow);
Initialize();
}
protected void CloseWindow()
{
window.Close();
}
protected bool? ShowDialog(Window windowToOpen)
{
windowToOpen.Owner = window;
return windowToOpen.ShowDialog();
}
private void Initialize()
{
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
window.DataContext = this;
}
protected void DisplayAlertAndLogError(string message, Exception ex)
{
log.Error(message, ex);
MessageBox.Show(message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
What's wrong with this picture?
Instead of displaying a nice picture of a prehistoric plant, the string of the location of the bitmap is being displayed!
Here's the XAML (snippet):
<DataTemplate x:Key="YoungPicCell">
<StackPanel Orientation="Horizontal">
<Image Height="200" Width="200" Stretch="None" Source="{Binding Path=YoungPicBmp}" />
</StackPanel>
</DataTemplate>
The filenames (and other data) are loaded at runtime from an XML file.
Here is the data being loaded from the XML file at runtime:
public class LVData
{
public string Name { get; set; }
public string YoungPic { get; set; }
public BitmapSource YoungPicBmp { get { return new BitmapImage(new Uri("{YoungPic}")); } }
public string MediumPic { get; set; }
public BitmapSource MediumPicBmp { get { return new BitmapImage(new Uri("{MediumPic}")); } }
public string AdultPic { get; set; }
public BitmapSource AdultPicBmp { get { return new BitmapImage(new Uri("{AdultPic}")); } }
public bool SaltWater { get; set; }
public bool FreshWater { get; set; }
public bool Grasslands { get; set; }
public bool Swamp { get; set; }
public bool TropicalForest { get; set; }
public bool Forest { get; set; }
public bool ForestEdge { get; set; }
public bool Sand { get; set; }
public bool Coastal { get; set; }
public bool RiverBorder { get; set; }
public bool LakeBorder { get; set; }
public bool Floodplain { get; set; }
}
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//called when a property is changed
protected void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
private ObservableCollection<LVData> _plantList = new ObservableCollection<LVData>();
public ObservableCollection<LVData> lsvData
{
get { return _plantList; }
set { _plantList = value; RaisePropertyChanged("lsvData"); }
}
public void PopulateDataFromXML(string filename)
{
XDocument loaded = XDocument.Load(#"DinoIslandPlants.xml");
var Plants = from x in loaded.Descendants("Plants")
select new
{
Name = x.Descendants("Name").First().Value,
YoungPic = x.Descendants("YoungPic").First().Value,
MediumPic = x.Descendants("MediumPic").First().Value,
AdultPic = x.Descendants("AdultPic").First().Value,
SaltWater = x.Descendants("SaltWater").First().Value,
FreshWater = x.Descendants("FreshWater").First().Value,
Grasslands = x.Descendants("Grasslands").First().Value,
Swamp = x.Descendants("Swamp").First().Value,
TropicalForest = x.Descendants("TropicalForest").First().Value,
Forest = x.Descendants("Forest").First().Value,
ForestEdge = x.Descendants("ForestEdge").First().Value,
Sand = x.Descendants("Sand").First().Value,
Coastal = x.Descendants("Coastal").First().Value,
RiverBorder = x.Descendants("RiverBorder").First().Value,
LakeBorder = x.Descendants("LakeBorder").First().Value,
Floodplain = x.Descendants("Floodplain").First().Value
};
foreach (var _plant in Plants)
{
_plantList.Add(new LVData {
Name = _plant.Name,
YoungPic = _plant.YoungPic,
MediumPic = _plant.MediumPic,
AdultPic = _plant.AdultPic,
SaltWater = Convert.ToBoolean(_plant.SaltWater),
FreshWater = Convert.ToBoolean(_plant.FreshWater),
Grasslands = Convert.ToBoolean(_plant.Grasslands),
Swamp = Convert.ToBoolean(_plant.Swamp),
TropicalForest = Convert.ToBoolean(_plant.TropicalForest),
Forest = Convert.ToBoolean(_plant.Forest),
Sand = Convert.ToBoolean(_plant.Sand),
Coastal = Convert.ToBoolean(_plant.Coastal),
RiverBorder = Convert.ToBoolean(_plant.RiverBorder),
LakeBorder = Convert.ToBoolean(_plant.LakeBorder),
Floodplain = Convert.ToBoolean(_plant.Floodplain)
});
}
RaisePropertyChanged("lsvData");
}
}
When binding to an Image control you need to bind to a BitmapSource. This should be pretty straight forward. Change the type of the property (or add a new one) to BitmapSource and then in the get do something like this:
... get { return new BitmapImage(new Uri("{PathToImage}")); }
where PathToImage is a recognizable path to the image you want to display.
I have a datagridview that I am binding to a class. I add to the class but the datagridview is not updating.
My bind:
ScannedChecks = new ScannedChecks();
ScannedChecks.AddCheck(DateTime.Now, "22222", "checknumdd", "routingdd", _checkData, 4);
dataGridView1.DataSource = ScannedChecks;
I went ahead and did the AddCheck to see if it was reaching the datagridview and it isn't... The class is being updated though.
My class:
namespace SSS.Ckentry
{
public class ScannedChecks : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ScannedChecks()
{
ScannedChecksCollection = new ObservableCollection<ScannedCheck>();
}
public void AddCheck(DateTime checkDate, string accountNumber, string checkNumber, string bankRoutingNumber, string bankAccountNumber, decimal checkAmount)
{
var scc = new ScannedCheck
{
CheckDate = checkDate,
AccountNumber = accountNumber,
CheckNumber = checkNumber,
BankRoutingNumber = bankRoutingNumber,
BankAccountNumber = bankAccountNumber,
CheckAmount = checkAmount,
};
ScannedChecksCollection.Add(scc);
}
public ObservableCollection<ScannedCheck> ScannedChecksCollection { get; set; }
public class ScannedCheck
{
public DateTime CheckDate { get; set; }
public string AccountNumber { get; set; }
public string CheckNumber { get; set; }
public string BankRoutingNumber { get; set; }
public string BankAccountNumber { get; set; }
public decimal CheckAmount { get; set; }
}
}
}
Can anyone tell me what I am doing wrong?
Thanks much!
If you ever replace the ScannedChecksCollection with a new ScannedChecksCollection, the property setter should fire the PropertyChanged exent.
private ObservableCollection<ScannedCheck> scannedChecksCollection;
public ObservableCollection<ScannedCheck> ScannedChecksCollection {
get
{
return scannedChecksCollection;
}
set
{
if (value != scannedChecksCollection)
{
value = scannedChecksCollection;
NotifyPropertyChanged("ScannedChecksCollection");
}
}
}
private void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
If checks are modifiable, ScannedCheck should implement INotifyPropertyChanged
Shouldn't you be doing
dataGridView1.DataSource = ScannedChecks.ScannedChecksCollection;