2010-08-25 29 views
5

Cập nhật: Tôi đã kiểm tra câu trả lời trước khi tôi kiểm tra đầy đủ nó vẫn không hoạt động. Tôi đã cập nhật mã dưới đây, do đó bạn chỉ có thể dán vào một dự án WinForms trống và nó sẽ biên dịch.ComboBox sẽ không cập nhật danh sách hiển thị trừ khi bạn thay đổi lựa chọn đầu tiên

CẬP NHẬT: Tôi đã tìm thấy rằng nếu tôi thay đổi mục đã chọn trên ComboBox thành bất kỳ mục nào khác, nó bây giờ hoạt động như mong đợi (trong mã của tôi dưới đây tôi sẽ chuyển từ test1 sang test2). Vì tôi chưa nhận được bất kỳ câu trả lời nào, tôi đã thay đổi câu hỏi này.

Tại sao tôi phải thay đổi thành một mục khác trong hộp tổ hợp trước khi nó hiển thị những thay đổi tôi thực hiện cho nguồn dữ liệu cơ bản?

Đây là trường hợp kiểm tra nhanh về những gì đang xảy ra.

  1. Thay đổi test1 để test1asdf văn bản trong txtBroken
  2. nhấp chuột tắt để thực hiện thay đổi
  3. văn bản trong combo box không cập nhật.
  4. Thay đổi combo box để Test2
  5. thay đổi test2-test2asdf văn bản trong txtBroken
  6. bấm tắt để thực hiện thay đổi
  7. văn bản trong combo box ngay lập tức cho thấy 'test2asdf' vẫn hiển thị test1 cho mục đầu tiên trong danh sách thả xuống
  8. thay đổi test1
  9. màn combo box test1 hộp văn bản hiển thị test1asdf
  10. cập nhật văn bản b bò để test1asd
  11. combo box ngay lập tức hiển thị test1asd

khác hơn đằng sau hậu trường thay đổi mục đã chọn vào tải và thay đổi nó trở lại (điều này có vẻ như một hack như vậy) làm thế nào tôi có thể sửa lỗi này?


Tôi có một databound combo box để một BindingSource ràng buộc với một List<Holder> nó có Holder.Name như giá trị hiển thị của nó. Tôi cũng có một hộp văn bản ràng buộc với Holder.Name nhưng nếu tôi thay đổi văn bản trong hộp văn bản, nó sẽ không thay đổi nội dung được hiển thị trong hộp tổ hợp. Thay đổi các mục đã chọn và thay đổi lại sẽ hiển thị văn bản được cập nhật trong hộp văn bản, nhưng vẫn sẽ có giá trị cũ được hiển thị trong hộp tổ hợp. Làm cách nào để tôi tạo mục trong bản cập nhật hộp kết hợp?

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 

namespace Sandbox_Form 
{ 
    public class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      lstBroken = new BindingList<Holder>(); 
      lstBroken.Add(new Holder("test1")); 
      lstBroken.Add(new Holder("test2")); 
      bsBroken = new BindingSource(lstBroken, null); 
      cmbBroken.DataSource = bsBroken; 
      cmbBroken.DisplayMember = "Name"; 
      cmbBroken.SelectedIndex = 0; 
      txtBroken.DataBindings.Add("Text", bsBroken, "Name"); 
      txtBroken.TextChanged += new EventHandler(txtBroken_TextChanged); 

     } 

     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
     } 

     void txtBroken_TextChanged(object sender, EventArgs e) 
     { 
      ((Control)sender).FindForm().Validate(); 
     } 
     private BindingSource bsBroken; 
     private BindingList<Holder> lstBroken; 
     private ComboBox cmbBroken; 
     private TextBox txtBroken; 
     private Label label1; 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.cmbBroken = new System.Windows.Forms.ComboBox(); 
      this.txtBroken = new System.Windows.Forms.TextBox(); 
      this.label1 = new System.Windows.Forms.Label(); 
      this.SuspendLayout(); 
      // 
      // cmbBroken 
      // 
      this.cmbBroken.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 
      this.cmbBroken.FormattingEnabled = true; 
      this.cmbBroken.Location = new System.Drawing.Point(12, 32); 
      this.cmbBroken.Name = "cmbBroken"; 
      this.cmbBroken.Size = new System.Drawing.Size(94, 21); 
      this.cmbBroken.TabIndex = 0; 
      // 
      // txtBroken 
      // 
      this.txtBroken.Location = new System.Drawing.Point(13, 60); 
      this.txtBroken.Name = "txtBroken"; 
      this.txtBroken.Size = new System.Drawing.Size(93, 20); 
      this.txtBroken.TabIndex = 1; 
      // 
      // label1 
      // 
      this.label1.AutoSize = true; 
      this.label1.Location = new System.Drawing.Point(13, 13); 
      this.label1.Name = "label1"; 
      this.label1.Size = new System.Drawing.Size(41, 13); 
      this.label1.TabIndex = 2; 
      this.label1.Text = "Broken"; 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(284, 262); 
      this.Controls.Add(this.label1); 
      this.Controls.Add(this.txtBroken); 
      this.Controls.Add(this.cmbBroken); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.ResumeLayout(false); 
      this.PerformLayout(); 

     } 

     #endregion 

     private void cmbWorks_SelectedIndexChanged(object sender, EventArgs e) 
     { 

     } 
    } 
    public class Holder 
    { 
     public Holder(string name) 
     { 
      Name = name; 
     } 
     private string _Name; 
     public string Name 
     { 
      get { return _Name; } 
      set 
      { 
       _Name = value; 
      } 
     } 
    } 
} 

Nếu tôi liên kết với một List<String> thay vì sử dụng Holder.Name nó hoạt động như mong đợi (đây chỉ là một đơn giản mock-up, lớp thực có nhiều hơn chỉ là một tên do đó, một danh sách các chuỗi sẽ không hoạt động). Tôi nghĩ rằng đây là một đầu mối cho những gì là sai, nhưng tôi không biết nó là gì. Sử dụng một Observable thay vì một danh sách không tạo ra sự khác biệt nào.

+0

Thực tế đặt txtBackupName datacontext thành mục đã chọn của cboJobSelector, sau đó liên kết với thuộc tính Tên, làm liên kết hiện tại của bạn với thuộc tính văn bản của hộp tổ hợp. Theo như tôi biết hộp kết hợp sẽ không cập nhật nguồn gốc nếu bạn thay đổi thuộc tính văn bản hiện tại của nó. –

+0

@LnDCobra Tôi làm như thế nào? –

+0

@Scott Tôi không chắc chắn làm thế nào chính xác để làm điều đó trong mã, tôi biết làm thế nào để làm điều đó xaml, nhưng tôi có thể hỏi tại sao bạn đang sử dụng ràng buộc với winforms? và không chỉ sử dụng WPF? –

Trả lời

18

Sử dụng BindingList thay vì List. Nó được thiết kế để giải quyết các vấn đề như vậy. Dinesh Chandnani, một thành viên của.Đội khách hàng NET, tình trạng sau đây trong một blog post:

BindingList<T> là mới generic thực hiện IBindingList mà cháy ListChanged sự kiện khi mục được thêm/gỡ bỏ/chèn/etc. từ danh sách . bindingSource móc vào các sự kiện này và do đó "nhận thức" những thay đổi này và có thể thông báo cho các điều khiển bị ràng buộc thos BindingSource này.

Tôi đã có thể tạo lại sự cố bạn đã mô tả trong mục nhập đã cập nhật của mình, nhưng không tạo lại hoàn toàn vấn đề ban đầu mà không cần chỉnh sửa mã một chút.

Bằng cách sử dụng BindingList<Holder> Tôi đã có thể nhận được phản hồi ngay lập tức khi lấy nét bên trái hộp văn bản. Có thể nhận các cập nhật tức thời bằng cách sử dụng phương thức quá tải khi thêm một ràng buộc dữ liệu mới. Tôi cũng đặt trực tiếp số của BindingSource kể từ khi sử dụng một số nulldataMember trong hàm tạo quá tải không mang lại hành vi mong đợi.

Dưới đây là đoạn code tôi đã kết thúc với dựa trên mẫu mã của bạn:

public partial class Form1 : Form 
{ 
    private BindingSource bs; 
    private BindingList<Holder> bList; 

    public Form1() 
    { 
     InitializeComponent(); 

     bList = new BindingList<Holder>(); 
     bList.Add(new Holder("test1")); 
     bList.Add(new Holder("test2")); 

     bs = new BindingSource(); 
     bs.DataSource = bList; 

     cmb.DataSource = bs; 
     cmb.DisplayMember = "Name"; 
     cmb.ValueMember = "Name"; 

     // updates when focus leaves the textbox 
     txt.DataBindings.Add("Text", bs, "Name"); 

     // updates when the property changes 
     //txt.DataBindings.Add("Text", bs, "Name", false, DataSourceUpdateMode.OnPropertyChanged); 
    } 
} 

luận ra là người đầu tiên txt ràng buộc và bỏ một bên dưới nó để xem DataSourceUpdateMode.OnPropertyChanged trong hành động.

Dưới đây là một số BindingList nguồn:

1) Thay bsBroken = new BindingSource(lstBroken, null); với:

bsBroken = new BindingSource(); 
bsBroken.DataSource = lstBroken; 

Hoặc trong một dòng: bsBroken = new BindingSource() { DataSource = lstBroken };

Điều này mang lại hành vi mong đợi với một phản ứng ngay lập tức với những thay đổi (tôi cũng đã đề cập đến điều này trước đây). Làm không sử dụng quá tải chấp nhận dataMember và đặt thành giá trị rỗng. Làm như vậy sẽ gây ra hành vi lỗi bạn đang gặp phải.

2) Sau khi thực hiện ở trên, tôi thấy không cần sự kiện txtBroken_TextChanged. Hãy chú ý phân bổ xử lý sự kiện để kiểm tra, nhưng bạn sẽ có thể loại bỏ nó hoàn toàn.

+0

Tôi đã cấp cho bạn khoản tín dụng mà không kiểm tra đầy đủ. nó vẫn hoạt động giống với danh sách ràng buộc. Tôi sẽ dán một mẫu mã làm việc hoàn toàn vào chủ đề của tôi. –

+0

@Scott Tôi đã cập nhật bài đăng của mình (xem ** EDIT ** ở trên) và đã có thể khắc phục sự cố của bạn. Cập nhật nhiệm vụ 'BindingSource.DataSource' và bạn nên làm tốt. –

+0

Tôi đưa ra câu trả lời được chấp nhận cho bạn. Tuy nhiên tôi sẽ giữ cho sự kiện TextChanged bởi vì theo cách đó, nó sẽ cập nhật văn bản trong hộp kết hợp khi bạn nhập thay vì nhấp vào trước khi cập nhật và tôi thích kiểu trực quan hơn đang chờ bạn nhấp vào. –

Các vấn đề liên quan