在我的應用程序中,我有一張表,其中包含組織內各個區域的數據,其中包含關於每個區域的統計數據的相關表格。爲簡單起見,我會將它們表示爲:將文本框綁定到BindingSource IList屬性中的特定DataRowView
____________ ________________ ________________
|Region | |RegionHasDemo | |DemoCategories|
| |1 *| |* 1| |
|-RegionID |----------|-RegionID |----------|-CatID |
|-City | |-CatID | |-SortOrder |
|-Zip | |-Population | |-Archive |
|-State | |______________| |______________|
|__________|
DemoCategories表包含人口統計類型。例如,讓我們說RegionHasDemo代表我的地區的年齡人口。 DemoCategories中的CatID將是Age20to30,Age20to40等等的值,以便RegionHasDemo代表所有地區的年齡組人口。
在我的應用程序中,我想創建一個表單來添加區域數據以及所有相關數據。爲此,我創建了兩個綁定源,一個用於RegionData,另一個用於RegionHasDemo,它包含RegionData,因爲它是DataSource。出於各種原因,我希望通過將單個文本框綁定到RegionHasDemoBindingSource的List屬性中包含的DataRowViews來輸入RegionHasDemo的數據。請注意,我不想使用網格視圖。
這裏是我用來每次綁定到文本框的RegionData改變當前屬性的代碼:
注:表名是從我的樣本,RegionData =單位不同; RegionHasDemo = UnitExp; DemoCategories = CatExp。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace DBsample
{
public partial class Form1 : Form
{
private DataTable DataSource;
private string relatedTableName;
/// <summary>
/// Holsd the values needed to define my text box rows and
/// relate them to the table containing their human readable
/// names, sort order, and active record status.
/// </summary>
private struct textBoxRow
{
public string Key { get; set; }
public TextBox TBox { get; set; }
public Label NameLabel { get; set; }
public string Name { get; set; }
public int Value { get; set; }
}
textBoxRow[] rows;
public Form1()
{
InitializeComponent();
DataSource = injuryDB.UnitExp;
relatedTableName = "CatExpUnitExp";
}
private void Form1_Load(object sender, EventArgs e)
{
this.uNITSTableAdapter.Fill(this.injuryDB.UNITS);
this.catExpTableAdapter1.Fill(this.injuryDB.CatExp);
this.unitExpTableAdapter1.Fill(this.injuryDB.UnitExp);
// Fill data table
// Associate them in the struct in sorted order
// Get a list of categories
DataTable catTable = DataSource.ParentRelations[relatedTableName].ParentTable;
// Sort them while leaving out the ones we don't want
List<DataRow> tbr = (from r in catTable.AsEnumerable()
where r.Field<bool>("ActiveRecord")
orderby r.Field<int>("SortOrder")
select r).ToList();
// The rows we are going to show
rows = new textBoxRow[tbr.Count];
tableLayoutPanel1.RowStyles.Clear();
int rowIndex = 0;
// Create rows and add them to the form
foreach (DataRow r in tbr)
{
textBoxRow tRow = new textBoxRow();
Label lbl = new Label();
lbl.Text = r.Field<string>("CatName");
TextBox tb = new TextBox();
tRow.Key = r.Field<string>("Category");
tRow.Name = r.Field<string>("CatName");
tRow.TBox = tb;
tRow.NameLabel = lbl;
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
tableLayoutPanel1.Controls.Add(tRow.NameLabel, 0, rowIndex);
tableLayoutPanel1.Controls.Add(tRow.TBox, 1, rowIndex);
rows[rowIndex] = tRow;
rowIndex++;
}
// Refresh the bindings in the text boxes when the current item changes
unitCatExpBindingSource.CurrentItemChanged += currentItemChanged;
currentItemChanged(null, null);
}
private void uNITSBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
bool validated = this.Validate();
if(validated == true)
Debug.WriteLine("Validated data to be saved");
else
Debug.WriteLine("Did not validate data to be saved");
this.uNITSBindingSource.EndEdit();
int recordsUpdated = this.tableAdapterManager.UpdateAll(this.injuryDB);
Debug.WriteLine(string.Format("{0} records were changed", recordsUpdated));
}
private void currentItemChanged(object sender, EventArgs e)
{
if (rows == null) return;
// For some reason I have to pass this into the bindingSource's find method instead of a
// straight string of the column name. It has something to do with the fact that we are
// binding to a data relation instead of a DataTable i think. Wadded through so many forums for this...
PropertyDescriptor pdc = unitCatExpBindingSource.CurrencyManager.GetItemProperties()["Cat"];
// Rebind each text box row
foreach (textBoxRow tBoxRow in rows)
{
tBoxRow.TBox.DataBindings.Clear();
// If the record doesn't exist then that means the population for that group is zero
tBoxRow.TBox.Text = "0";
//tbr.TBox.Leave -= existingRecordTBoxChanged;
//tbr.TBox.Leave -= nonExistingRecordTBoxChanged;
// Get the index of the source I want to bind to using the text
int bindingIndex = unitCatExpBindingSource.Find(pdc, tBoxRow.Key);
//object bs = unitCatExpBindingSource[bindingIndex];
if (bindingIndex >= 0)
{
Binding b = tBoxRow.TBox.DataBindings.Add("Text", unitCatExpBindingSource[bindingIndex], "Jumps", true);
}
else
{
// TODO: Create an event that adds a new to the demo table if number not 0
}
}
}
// TODO: for this to work the delete options of the relationships
// for Units -> category tables need to be set to cascade
private void existingRecordTBoxChanged(object sender, EventArgs e)
{
TextBox tBox = (TextBox)sender;
if (tBox.Text == "" || tBox.Text == "0")
{
//DataRow d = (DataRow)tBox.DataBindings[0].DataSource;
}
}
private void nonExistingRecordTBoxChanged(object sender, EventArgs e)
{
TextBox tBox = (TextBox)sender;
if (!(tBox.Text == "" || tBox.Text == "0"))
{
// TODO: Add record to the database
}
}
}
<code>
我的問題是,雖然當我的結合似乎是工作好觀看,即文本框,當我通過單位導航改變。這些更改不保存到數據庫。我在文本框中所做的更改將保留在DataSet中(當我離開記錄並返回它們時保持不變),但是當我保存dataSet關閉表單並將其重新打開時,所做的更改就消失了。就好像dataSet沒有被通知那些值被改變了。此外,如果我將相關數據放在數據網格的一側,則可以修改DataGridView中的數據,並且可以保存數據。另外,當我更改我的文本框中的數據時,新值將顯示在DataGridView中,但仍然不會保存...
我想知道是我用來將文本框綁定到數據正確。這意味着,我可以以包含在綁定源中的DataRowView的形式綁定數據,並期望它的行爲與我直接使用綁定源相同?
非常感謝您的幫助。我希望我已經提供了足夠的信息讓你繼續。請記住,此代碼示例來自原型。我明白這不是最佳做法。這表示我會很感激任何建設性的批評。
更新:經過一些進一步的測試,並在代碼中放入一些換行符後,我發現雖然大多數文本框都不起作用,但其中一個文本框卻起作用。在比較文本框中的屬性後,我發現沒有工作的文本框的屬性IsEdit和delayBeginEdit設置爲false。是我綁定文本框的方式,所以我只能綁定一個控件到BindingSource? –