2014-02-10 64 views
0

我有一個使用BindingSource,BindingNavigator和TableAdapter控件具有數據綁定控件(詳細視圖)的Windows窗體應用程序。我想創建一個只讀的單個記錄。我讀過很多文章,並嘗試了幾件事,但沒有運氣。我在Navigator上處理了DeleteItem,但很快就意識到你仍然可以改變它,Move會保存更改。只讀記錄

我已閱讀過關於IEditableObject和過濾器,但不知道如何用上述控件實現這一點。

+0

你能告訴我們你已經試過了嗎? – MCollard

+0

正如我所提到的,我在網上閱讀了幾十篇文章,測試那些聽起來似乎合理的文章,但沒有做到我想要的。只需搜索「BindingNavigator」和「只讀」或「防止刪除更改」即可看到一些內容。我沒有看到發佈代碼或鏈接沒有完成任務的好處... –

+0

我想通過設置BindingSource的Filter屬性,我可以隱藏感興趣的記錄。但是,我真的只想防止更改或刪除(如果嘗試更改或刪除,也會顯示MessageBox),但仍允許顯示它。 –

回答

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()函數?綜觀其他事件處理程序,我們可以看到,他們都稱驗證:

private void OnMoveFirst(object sender, EventArgs e) { 
     if (Validate()) { 
      if (bindingSource != null) { 
       bindingSource.MoveFirst(); 
       RefreshItemsInternal(); 
      } 
     } 

有人可能導致認爲BindingNavigator驗證事件可能火了,我們可以顯示一個MessageBox和集合E。Cancel = true,但由於某種原因,它沒有觸發任何按鈕點擊。

我終於採取的方法(有點缺憾看)是處理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; 
       } 
      } 
     } 
    } 

如果唯一控件是文本框,你可能更喜歡使用「ctrl.ReadOnly = true」而不是「ctrl.Enabled = false」。

我仍在尋找一種更簡單,更優雅的方式來捕捉變化並阻止它們...