Attention! This model is just an example. Your subject area may be more complicated, or completely different. The model used in this article is simplified as much as possible in order not to clutter up the description of working with components with the description of creating and modifying the data model. |
Important! This must be done with administrator rights. Like other actions with protected directories. |
chdir "c:\Program Files (x86)\FirebirdClient"
gacutil /l FirebirdSql.Data.FirebirdClient
Microsoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.0
c (Microsoft Corporation). .
:
FirebirdSql.Data.FirebirdClient, Version=4.10.0.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c, processorArchitecture=MSIL
= 1
gacutil /i FirebirdSql.Data.FirebirdClient.dll
gacutil /i EntityFramework.Firebird.dll
Author's note It's funny, but for some reason these files are not in the previous archive with compiled dll libraries, but they are present in the archive with source codes. |
<system.data>
<DbProviderFactories>
<add name="FirebirdClient Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".Net Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=4.10.0.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c" />
Comment All this is valid for version 4.10.0. |
<add name="DbModel" connectionString="character set=UTF8; data source=localhost;initial catalog=examples; port number=3050; user id=sysdba; dialect=3; isolationlevel=Snapshot; pooling=True; password=masterkey;" providerName="FirebirdSql.Data.FirebirdClient" />
password=masterkey;
A note about working with Firebird 3.0 Unfortunately, the current ADO .Net provider for Firebird (version 4.10.0) does not support SRP authentication (by default in Firebird 3.0). Therefore, if you want to work with Firebird 3.0, then you need to change some settings in firebird.conf (or in databases.conf for a specific database) in order for Firebird to work through Legacy_Auth. To do this, change the following settings: UserManager = Legacy_UserManager Save settings. After that, you need to create a SYSDBA user and other users using Legacy_UserManager. |
[Table("Firebird.INVOICE")] public partial class INVOICE { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public INVOICE() { INVOICE_LINES = new HashSet<INVOICE_LINE>(); } [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int INVOICE_ID { get; set; } public int CUSTOMER_ID { get; set; } public DateTime? INVOICE_DATE { get; set; } public double? TOTAL_SALE { get; set; } public short PAID { get; set; } public virtual CUSTOMER CUSTOMER { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection<INVOICE_LINE> INVOICE_LINES { get; set; } }
public decimal TOTAL_SALE { get; set; }
public partial class DbModel : DbContext { public DbModel() : base("name=DbModel") { } public virtual DbSet<CUSTOMER> CUSTOMERS { get; set; } public virtual DbSet<INVOICE> INVOICES { get; set; } public virtual DbSet<INVOICE_LINE> INVOICE_LINES { get; set; } public virtual DbSet<PRODUCT> PRODUCTS { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<CUSTOMER>() .Property(e => e.ZIPCODE) .IsFixedLength(); modelBuilder.Entity<CUSTOMER>() .HasMany(e => e.INVOICES) .WithRequired(e => e.CUSTOMER) .WillCascadeOnDelete(false); modelBuilder.Entity<PRODUCT>() .HasMany(e => e.INVOICE_LINES) .WithRequired(e => e.PRODUCT) .WillCascadeOnDelete(false); modelBuilder.Entity<INVOICE>() .HasMany(e => e.INVOICE_LINES) .WithRequired(e => e.INVOICE) .WillCascadeOnDelete(false); } }
modelBuilder.Entity<PRODUCT>() .Property(p => p.PRICE) .HasPrecision(15, 2); modelBuilder.Entity<INVOICE>() .Property(p => p.TOTAL_SALE) .HasPrecision(15, 2); modelBuilder.Entity<INVOICE_LINE>() .Property(p => p.SALE_PRICE) .HasPrecision(15, 2); modelBuilder.Entity<INVOICE_LINE>() .Property(p => p.QUANTITY) .HasPrecision(15, 0);
DbModel dbContext = new DbModel();
static class AppVariables { private static DbModel dbContext = null; /// <summary> /// /// </summary> public static DateTime StartDate { get; set; } /// <summary> /// /// </summary> public static DateTime FinishDate { get; set; } /// <summary> /// () /// </summary> /// <returns></returns> public static DbModel CreateDbContext() { dbContext = dbContext ?? new DbModel(); return dbContext; } }
private void MainForm_Load(object sender, EventArgs e) { var dialog = new LoginForm(); if (dialog.ShowDialog() == DialogResult.OK) { var dbContext = AppVariables.getDbContext(); try { string s = dbContext.Database.Connection.ConnectionString; var builder = new FbConnectionStringBuilder(s); builder.UserID = dialog.UserName; builder.Password = dialog.Password; dbContext.Database.Connection.ConnectionString = builder.ConnectionString; // dbContext.Database.Connection.Open(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); Application.Exit(); } } else Application.Exit(); }
var dbContext = AppVariables.getDbContext()
private void LoadCustomersData() { dbContext.CUSTOMERS.Load(); var customers = dbContext.CUSTOMERS.Local; bindingSource.DataSource = customers.ToBindingList(); } private void CustomerForm_Load(object sender, EventArgs e) { LoadCustomersData(); dataGridView.DataSource = bindingSource; dataGridView.Columns["CUSTOMER_ID"].Visible = false; }
private void LoadCustomersData() { var dbContext = AppVariables.getDbContext(); dbContext.CUSTOMERS.Load(); var customers = from customer in dbContext.CUSTOMERS.Local orderby customer.NAME select new customer; bindingSource.DataSource = customers.ToBindingList(); }
public static class DbExtensions { // private class IdResult { public int Id { get; set; } } // IQueryable BindingList public static BindingList<T> ToBindingList<T> (this IQueryable<T> source) where T : class { return (new ObservableCollection<T>(source)).ToBindingList(); } // public static int NextValueFor(this DbModel dbContext, string genName) { string sql = String.Format( "SELECT NEXT VALUE FOR {0} AS Id FROM RDB$DATABASE", genName); return dbContext.Database.SqlQuery<IdResult>(sql).First().Id; } // DbSet // public static void DetachAll<T>(this DbModel dbContext, DbSet<T> dbSet) where T : class { foreach (var obj in dbSet.Local.ToList()) { dbContext.Entry(obj).State = EntityState.Detached; } } // public static void Refresh(this DbModel dbContext, RefreshMode mode, IEnumerable collection) { var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; objectContext.Refresh(mode, collection); } // public static void Refresh(this DbModel dbContext, RefreshMode mode, object entity) { var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; objectContext.Refresh(mode, entity); } }
Comment In Web applications, the context usually lives for a very short time, and the new context does not have a full cache. |
private void LoadCustomersData() { var dbContext = AppVariables.getDbContext(); // // // dbContext.DetachAll(dbContext.CUSTOMERS); var customers = from customer in dbContext.CUSTOMERS orderby customer.NAME select customer; bindingSource.DataSource = customers.ToBindingList(); } private void CustomerForm_Load(object sender, EventArgs e) { LoadCustomersData(); dataGridView.DataSource = bindingSource; dataGridView.Columns["INVOICES"].Visible = false; dataGridView.Columns["CUSTOMER_ID"].Visible = false; dataGridView.Columns["NAME"].HeaderText = "Name"; dataGridView.Columns["ADDRESS"].HeaderText = "Address"; dataGridView.Columns["ZIPCODE"].HeaderText = "ZipCode"; dataGridView.Columns["PHONE"].HeaderText = "Phone"; }
private void btnAdd_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); // var customer = (CUSTOMER)bindingSource.AddNew(); // using (CustomerEditorForm editor = new CustomerEditorForm()) { editor.Text = " "; editor.Customer = customer; // editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) { if (editor.DialogResult == DialogResult.OK) { try { // // customer.CUSTOMER_ID = dbContext.NextValueFor("GEN_CUSTOMER_ID"); // dbContext.CUSTOMERS.Add(customer); // dbContext.SaveChanges(); // dbContext.Refresh(RefreshMode.StoreWins, customer); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); // fe.Cancel = true; } } else bindingSource.CancelEdit(); }; // editor.ShowDialog(this); } }
private void btnEdit_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); // var customer = (CUSTOMER)bindingSource.Current; // using (CustomerEditorForm editor = new CustomerEditorForm()) { editor.Text = " "; editor.Customer = customer; // editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) { if (editor.DialogResult == DialogResult.OK) { try { // dbContext.SaveChanges(); dbContext.Refresh(RefreshMode.StoreWins, customer); // bindingSource.ResetCurrentItem(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); // fe.Cancel = true; } } else bindingSource.CancelEdit(); }; // editor.ShowDialog(this); } }
public CUSTOMER Customer { get; set; } private void CustomerEditorForm_Load(object sender, EventArgs e) { edtName.DataBindings.Add("Text", this.Customer, "NAME"); edtAddress.DataBindings.Add("Text", this.Customer, "ADDRESS"); edtZipCode.DataBindings.Add("Text", this.Customer, "ZIPCODE"); edtPhone.DataBindings.Add("Text", this.Customer, "PHONE"); }
private void btnDelete_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); var result = MessageBox.Show(" ?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { // var customer = (CUSTOMER)bindingSource.Current; try { dbContext.CUSTOMERS.Remove(customer); // dbContext.SaveChanges(); // bindingSource.RemoveCurrent(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); } } }
public void LoadInvoicesData() { var dbContext = AppVariables.getDbContext(); // LINQ SQL var invoices = from invoice in dbContext.INVOICES where (invoice.INVOICE_DATE >= AppVariables.StartDate) && (invoice.INVOICE_DATE <= AppVariables.FinishDate) orderby invoice.INVOICE_DATE descending select new InvoiceView { Id = invoice.INVOICE_ID, Cusomer_Id = invoice.CUSTOMER_ID, Customer = invoice.CUSTOMER.NAME, Date = invoice.INVOICE_DATE, Amount = invoice.TOTAL_SALE, Paid = (invoice.PAID == 1) ? "Yes" : "No" }; masterBinding.DataSource = invoices.ToBindingList(); }
public class InvoiceView { public int Id { get; set; } public int Cusomer_Id { get; set; } public string Customer { get; set; } public DateTime? Date { get; set; } public decimal? Amount { get; set; } public string Paid { get; set; } public void Load(int Id) { var dbContext = AppVariables.getDbContext(); var invoices = from invoice in dbContext.INVOICES where invoice.INVOICE_ID == Id select new InvoiceView { Id = invoice.INVOICE_ID, Cusomer_Id = invoice.CUSTOMER_ID, Customer = invoice.CUSTOMER.NAME, Date = invoice.INVOICE_DATE, Amount = invoice.TOTAL_SALE, Paid = (invoice.PAID == 1) ? "Yes" : "No" }; InvoiceView invoiceView = invoices.ToList().First(); this.Id = invoiceView.Id; this.Cusomer_Id = invoiceView.Cusomer_Id; this.Customer = invoiceView.Customer; this.Date = invoiceView.Date; this.Amount = invoiceView.Amount; this.Paid = invoiceView.Paid; } }
private void btnAddInvoice_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); var invoice = dbContext.INVOICES.Create(); using (InvoiceEditorForm editor = new InvoiceEditorForm()) { editor.Text = " "; editor.Invoice = invoice; // editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) { if (editor.DialogResult == DialogResult.OK) { try { // invoice.INVOICE_ID = dbContext.NextValueFor("GEN_INVOICE_ID"); // dbContext.INVOICES.Add(invoice); // dbContext.SaveChanges(); // ((InvoiceView)masterBinding.AddNew()).Load(invoice.INVOICE_ID); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); // fe.Cancel = true; } } }; // editor.ShowDialog(this); } }
private void btnEditInvoice_Click(object sender, EventArgs e) { // var dbContext = AppVariables.getDbContext(); // var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id); if (invoice.PAID == 1) { MessageBox.Show(" , .", ""); return; } using (InvoiceEditorForm editor = new InvoiceEditorForm()) { editor.Text = "Edit invoice"; editor.Invoice = invoice; // editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) { if (editor.DialogResult == DialogResult.OK) { try { // dbContext.SaveChanges(); // CurrentInvoice.Load(invoice.INVOICE_ID); masterBinding.ResetCurrentItem(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); // fe.Cancel = true; } } }; // editor.ShowDialog(this); } }
public InvoiceView CurrentInvoice { get { return (InvoiceView)masterBinding.Current; } }
private void btnInvoicePay_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id); try { if (invoice.PAID == 1) throw new Exception(" , ."); invoice.PAID = 1; // dbContext.SaveChanges(); // CurrentInvoice.Load(invoice.INVOICE_ID); masterBinding.ResetCurrentItem(); } catch (Exception ex) { // MessageBox.Show(ex.Message, ""); } }
private void masterBinding_CurrentChanged(object sender, EventArgs e) { LoadInvoiceLineData(this.CurrentInvoice.Id); detailGridView.DataSource = detailBinding; }
private void LoadInvoiceLineData(int? id) { var dbContext = AppVariables.getDbContext(); var lines = from line in dbContext.INVOICE_LINES where line.INVOICE_ID == id select new InvoiceLineView { Id = line.INVOICE_LINE_ID, Invoice_Id = line.INVOICE_ID, Product_Id = line.PRODUCT_ID, Product = line.PRODUCT.NAME, Quantity = line.QUANTITY, Price = line.SALE_PRICE, Total = Math.Round(line.QUANTITY * line.SALE_PRICE, 2) }; detailBinding.DataSource = lines.ToBindingList(); }
public class InvoiceLineView { public int Id { get; set; } public int Invoice_Id { get; set; } public int Product_Id { get; set; } public string Product { get; set; } public decimal Quantity { get; set; } public decimal Price { get; set; } public decimal Total { get; set; } }
public InvoiceLineView CurrentInvoiceLine { get { return (InvoiceLineView)detailBinding.Current; } }
private void btnAddInvoiceLine_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); // - var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id); // - if (invoice.PAID == 1) { MessageBox.Show(" , - .", "Error"); return; } // - var invoiceLine = dbContext.INVOICE_LINES.Create(); invoiceLine.INVOICE_ID = invoice.INVOICE_ID; // using (InvoiceLineEditorForm editor = new InvoiceLineEditorForm()) { editor.Text = "Add invoice line"; editor.InvoiceLine = invoiceLine; // editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) { if (editor.DialogResult == DialogResult.OK) { try { // var invoiceIdParam = new FbParameter("INVOICE_ID", FbDbType.Integer); var productIdParam = new FbParameter("PRODUCT_ID", FbDbType.Integer); var quantityParam = new FbParameter("QUANTITY", FbDbType.Integer); // invoiceIdParam.Value = invoiceLine.INVOICE_ID; productIdParam.Value = invoiceLine.PRODUCT_ID; quantityParam.Value = invoiceLine.QUANTITY; // dbContext.Database.ExecuteSqlCommand( "EXECUTE PROCEDURE SP_ADD_INVOICE_LINE(@INVOICE_ID, @PRODUCT_ID, @QUANTITY)", invoiceIdParam, productIdParam, quantityParam); // // - CurrentInvoice.Load(invoice.INVOICE_ID); // LoadInvoiceLineData(invoice.INVOICE_ID); // masterBinding.ResetCurrentItem(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); // fe.Cancel = true; } } }; // editor.ShowDialog(this); } }
private void btnEditInvoiceLine_Click(object sender, EventArgs e) { var dbContext = AppVariables.getDbContext(); // - var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id); // - if (invoice.PAID == 1) { MessageBox.Show(" , .", "Error"); return; } // - var invoiceLine = invoice.INVOICE_LINES .Where(p => p.INVOICE_LINE_ID == this.CurrentInvoiceLine.Id) .First(); // using (InvoiceLineEditorForm editor = new InvoiceLineEditorForm()) { editor.Text = "Edit invoice line"; editor.InvoiceLine = invoiceLine; // editor.FormClosing += delegate (object fSender, FormClosingEventArgs fe) { if (editor.DialogResult == DialogResult.OK) { try { // var idParam = new FbParameter("INVOICE_LINE_ID", FbDbType.Integer); var quantityParam = new FbParameter("QUANTITY", FbDbType.Integer); // idParam.Value = invoiceLine.INVOICE_LINE_ID; quantityParam.Value = invoiceLine.QUANTITY; // dbContext.Database.ExecuteSqlCommand( "EXECUTE PROCEDURE SP_EDIT_INVOICE_LINE(@INVOICE_LINE_ID, @QUANTITY)", idParam, quantityParam); // // - CurrentInvoice.Load(invoice.INVOICE_ID); // LoadInvoiceLineData(invoice.INVOICE_ID); // masterBinding.ResetCurrentItem(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); // fe.Cancel = true; } } }; // editor.ShowDialog(this); } }
private void btnDeleteInvoiceLine_Click(object sender, EventArgs e) { var result = MessageBox.Show(" -?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { var dbContext = AppVariables.getDbContext(); // - var invoice = dbContext.INVOICES.Find(this.CurrentInvoice.Id); try { // - if (invoice.PAID == 1) throw new Exception(" , - ."); // var idParam = new FbParameter("INVOICE_LINE_ID", FbDbType.Integer); // idParam.Value = this.CurrentInvoiceLine.Id; // dbContext.Database.ExecuteSqlCommand( "EXECUTE PROCEDURE SP_DELETE_INVOICE_LINE(@INVOICE_LINE_ID)", idParam); // // - CurrentInvoice.Load(invoice.INVOICE_ID); // LoadInvoiceLineData(invoice.INVOICE_ID); // masterBinding.ResetCurrentItem(); } catch (Exception ex) { // MessageBox.Show(ex.Message, "Error"); } } }
public partial class InvoiceLineEditorForm : Form { public InvoiceLineEditorForm() { InitializeComponent(); } public INVOICE_LINE InvoiceLine { get; set; } private void InvoiceLineEditorForm_Load(object sender, EventArgs e) { if (this.InvoiceLine.PRODUCT != null) { edtProduct.Text = this.InvoiceLine.PRODUCT.NAME; edtPrice.Text = this.InvoiceLine.PRODUCT.PRICE.ToString("F2"); btnChooseProduct.Click -= this.btnChooseProduct_Click; } if (this.InvoiceLine.QUANTITY == 0) this.InvoiceLine.QUANTITY = 1; edtQuantity.DataBindings.Add("Value", this.InvoiceLine, "QUANTITY"); } private void btnChooseProduct_Click(object sender, EventArgs e) { GoodsForm goodsForm = new GoodsForm(); if (goodsForm.ShowDialog() == DialogResult.OK) { InvoiceLine.PRODUCT_ID = goodsForm.CurrentProduct.Id; edtProduct.Text = goodsForm.CurrentProduct.Name; edtPrice.Text = goodsForm.CurrentProduct.Price.ToString("F2"); } } }
var dbContext = AppVariables.getDbContext(); foreach (DataGridViewRow gridRows in dataGridView.SelectedRows) { int id = (int)gridRows.Cells["Id"].Value; // var product = dbContext.PRODUCTS.Find(id); // 10% decimal discount = 10.0m; product.PRICE = product.PRICE * (100 - discount) /100; } // // dbContext.SaveChanges();
var dbContext = AppVariables.getDbContext(); // using (var dbTransaction = dbContext.Database.BeginTransaction()) { string sql = "UPDATE PRODUCT " + "SET PRICE = PRICE * ROUND((100 - @DISCOUNT)/100, 2) " + "WHERE PRODUCT_ID = @PRODUCT_ID"; try { // var idParam = new FbParameter("PRODUCT_ID", FbDbType.Integer); var discountParam = new FbParameter("DISCOUNT", FbDbType.Decimal); // SQL var sqlCommand = dbContext.Database.Connection.CreateCommand(); sqlCommand.CommandText = sql; // , sqlCommand.Transaction = dbTransaction.UnderlyingTransaction; sqlCommand.Parameters.Add(discountParam); sqlCommand.Parameters.Add(idParam); // sqlCommand.Prepare(); // foreach (DataGridViewRow gridRows in dataGridView.SelectedRows) { int id = (int)gridRows.Cells["Id"].Value; // idParam.Value = id; discountParam.Value = 10.0m; // 10% // sql sqlCommand.ExecuteNonQuery(); } dbTransaction.Commit(); } catch (Exception ex) { dbTransaction.Rollback(); MessageBox.Show(ex.Message, "error"); } }
private void btnDiscount_Click(object sender, EventArgs e) { DiscountEditorForm editor = new DiscountEditorForm(); editor.Text = "Enter discount"; if (editor.ShowDialog() != DialogResult.OK) return; bool needUpdate = false; var dbContext = AppVariables.getDbContext(); var connection = dbContext.Database.Connection; // using (var dbTransaction = connection.BeginTransaction(IsolationLevel.Snapshot)) { dbContext.Database.UseTransaction(dbTransaction); string sql = "UPDATE PRODUCT " + "SET PRICE = ROUND(PRICE * (100 - @DISCOUNT)/100, 2) " + "WHERE PRODUCT_ID = @PRODUCT_ID"; try { // var idParam = new FbParameter("PRODUCT_ID", FbDbType.Integer); var discountParam = new FbParameter("DISCOUNT", FbDbType.Decimal); // SQL var sqlCommand = connection.CreateCommand(); sqlCommand.CommandText = sql; // sqlCommand.Transaction = dbTransaction; sqlCommand.Parameters.Add(discountParam); sqlCommand.Parameters.Add(idParam); // sqlCommand.Prepare(); // foreach (DataGridViewRow gridRows in dataGridView.SelectedRows) { int id = (int)gridRows.Cells["PRODUCT_ID"].Value; // idParam.Value = id; discountParam.Value = editor.Discount; // sql needUpdate = (sqlCommand.ExecuteNonQuery() > 0) || needUpdate; } dbTransaction.Commit(); } catch (Exception ex) { dbTransaction.Rollback(); MessageBox.Show(ex.Message, "error"); needUpdate = false; } } // <a href="http://ib-aid.com/download/docs/NET_DB.zip"></a> if (needUpdate) { // foreach (DataGridViewRow gridRows in dataGridView.SelectedRows) { var product = (PRODUCT)bindingSource.List[gridRows.Index]; dbContext.Refresh(RefreshMode.StoreWins, product); } bindingSource.ResetBindings(false); } }
Source: https://habr.com/ru/post/278405/
All Articles