我有一个Windows窗体应用程序,它具有数据绑定控件(详细信息视图),使用BindingSource,BindingNavigator和TableAdapter控件。我想将一条记录设为只读。我读了很多文章,没有运气就尝试了几件事。我在Navigator上处理了DeleteItem,但很快意识到你仍然可以更改它,Move会保存更改。
我已阅读有关IEditableObject和Filters的内容,但不知道如何使用上述控件实现此功能。
答案 0 :(得分:0)
您的情况可能会有所不同,但由于我想要以只读方式创建的特殊记录是以编程方式添加的,而其他记录是由用户输入的,我只需将BindingSource的Filter属性更改为:
field1 <> 'Special' AND field2 <> 'Record'
然后不会显示特殊记录。
但是,我真的想要显示记录,只是不允许更改或删除。
BindingSource和BindingNavigator之间的关系在BindingNavigator Class文档的备注中有解释。
但是,我下载了BindingNavigator.cs source code in C# .NET并找到了这些BindingNavigator按钮事件处理程序: OnMoveFirst, OnMovePrevious, OnMoveNext, OnMoveLast, OnAddNew, OnDelete, 并且每个只是调用BindingSource中的相关函数。
以下是感兴趣的内容:
private void OnDelete(object sender, EventArgs e) {
if (Validate()) {
if (bindingSource != null) {
bindingSource.RemoveCurrent();
RefreshItemsInternal();
}
}
}
我们可以看到Validate()函数,但它的开发人员文档不是很好:
// <include file="doc\BindingNavigator.uex" path='docs/doc[@for="BindingNavigator.Validate"]/*'>
// <devdoc>
// Triggers form validation. Used by the BindingNavigator's standard items when clicked. If a validation error occurs
// on the form, focus remains on the active control and the standard item does not perform its standard click action.
// Custom items may also use this method to trigger form validation and check for success before performing an action.
// </devdoc>
public bool Validate() {
bool validatedControlAllowsFocusChange;
return this.ValidateActiveControl(out validatedControlAllowsFocusChange);
}
有点嘿,因为它是公开的,我也可以称之为。他们都完成了:
/// <devdoc>
/// Refresh the state of the items when the state of the data changes.
/// </devdoc>
private void RefreshItemsInternal() {
// Block all updates during initialization
if (initializing) {
return;
}
// Call method that updates the items (overridable)
OnRefreshItems();
}
/// <include file="doc\BindingNavigator.uex" path='docs/doc[@for="BindingNavigator.OnRefreshItems"]/*'>
/// <devdoc>
/// Called when the state of the tool strip items needs to be refreshed to reflect the current state of the data.
/// Calls <see cref="RefreshItemsCore"> to refresh the state of the standard items, then raises the RefreshItems event.
/// </see>
protected virtual void OnRefreshItems() {
// Refresh all the standard items
RefreshItemsCore();
// Raise the public event
if (onRefreshItems != null) {
onRefreshItems(this, EventArgs.Empty);
}
}
/// <include file="doc\BindingNavigator.uex" path='docs/doc[@for="BindingNavigator.RefreshItemsCore"]/*'>
/// <devdoc>
/// Refreshes the state of the standard items to reflect the current state of the data.
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void RefreshItemsCore() {
int count, position;
bool allowNew, allowRemove;
// Get state info from the binding source (if any)
if (bindingSource == null) {
count = 0;
position = 0;
allowNew = false;
allowRemove = false;
}
else {
count = bindingSource.Count;
position = bindingSource.Position + 1;
allowNew = (bindingSource as IBindingList).AllowNew;
allowRemove = (bindingSource as IBindingList).AllowRemove;
}
// Enable or disable items (except when in design mode)
if (!DesignMode) {
if (MoveFirstItem != null) moveFirstItem.Enabled = (position > 1);
if (MovePreviousItem != null) movePreviousItem.Enabled = (position > 1);
if (MoveNextItem != null) moveNextItem.Enabled = (position < count);
if (MoveLastItem != null) moveLastItem.Enabled = (position < count);
if (AddNewItem != null) addNewItem.Enabled = (allowNew);
if (DeleteItem != null) deleteItem.Enabled = (allowRemove && count > 0);
if (PositionItem != null) positionItem.Enabled = (position > 0 && count > 0);
if (CountItem != null) countItem.Enabled = (count > 0);
}
// Update current position indicator
if (positionItem != null) {
positionItem.Text = position.ToString(CultureInfo.CurrentCulture);
}
// Update record count indicator
if (countItem != null) {
countItem.Text = DesignMode ? CountItemFormat : String.Format(CultureInfo.CurrentCulture, CountItemFormat, count);
}
}
所以我想出了以下内容以防止删除,这有效:
// First change bindingNavigator1's DeleteItem property from bindingNavigatorDeleteItem to (none)
// and then add a click event handler for the Delete button:
private void bindingNavigatorDeleteItem_Click(object sender, EventArgs e)
{
// prevent special record deletion
if ((textBox1.Text == "Special") && (textBox2.Text == "Record"))
{
MessageBox.Show("This record cannot be deleted.",
"Delete operation aborted",
MessageBoxButtons.OK,
MessageBoxIcon.Information,
MessageBoxDefaultButton.Button1);
}
else
{
if (this.Validate() && (this.bindingSource1 != null))
{
this.bindingSource1.RemoveCurrent();
this.bindingSource1.EndEdit();
this.tableAdapterManager.UpdateAll(this.dataSet1);
}
}
}
现在,防止变化呢?我为“保存”按钮添加了一个单击处理程序:
private void bindingNavigator1SaveItem_Click(object sender, EventArgs e)
{
if ((textBox1.Text == "Special") && (textBox2.Text == "Record"))
{
MessageBox.Show("Cannot change this record.",
"Save operation aborted",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
return;
}
try
{
this.Validate();
this.bindingSource1.EndEdit();
this.tableAdapterManager1.UpdateAll(this.DataSet1);
this.tableAdapter1.Fill(DataSet1.Customers);
this.bindingSource1.Position = this.DataSet1.Tables[0].Rows.Count;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
但是,此时,用户可以更改记录,然后单击其中一个移动按钮。现在看来TableAdapter?获得更新,但是如果没有单击“保存”按钮,更改永远不会写回数据库。也许我们可以在这里做得更好。
现在,还记得所有按钮调用的Validate()函数吗?查看其他事件处理程序,我们看到它们都调用Validate:
private void OnMoveFirst(object sender, EventArgs e) {
if (Validate()) {
if (bindingSource != null) {
bindingSource.MoveFirst();
RefreshItemsInternal();
}
}
可能会有人认为BindingNavigator Validating事件可能会触发,我们可以显示一个MessageBox并设置e.Cancel = true,但由于某种原因,它不会触发任何按钮点击。
我最终采用的方法(看起来有点kludgy)是为特殊记录的关键字段处理TextChanged事件并禁用所有控件:
private void textBox2_TextChanged(object sender, EventArgs e)
{
if (textBox2.Text == "Record")
{
foreach (Control ctrl in groupBox1.Controls)
{
if ((ctrl.GetType() == typeof(TextBox)) ||
(ctrl.GetType() == typeof(ComboBox)) ||
(ctrl.GetType() == typeof(CheckBox)))
{
ctrl.Enabled = false;
}
}
}
else
{
foreach (Control ctrl in groupBox1.Controls)
{
if ((ctrl.GetType() == typeof(TextBox)) ||
(ctrl.GetType() == typeof(ComboBox)) ||
(ctrl.GetType() == typeof(CheckBox)))
{
ctrl.Enabled = true;
}
}
}
}
如果唯一的控件是TextBoxes,您可能更喜欢使用“ctrl.ReadOnly = true”而不是“ctrl.Enabled = false”。
我仍然在寻找一种更简单,更优雅的方法来捕捉变化并阻止它们......