2010-03-01 25 views
15

Tôi muốn OpenFileDialog xuất hiện khi người dùng nhấp vào một ô, sau đó hiển thị kết quả trong ô.DataGridView ném "InvalidOperationException: Operation không hợp lệ ..." khi thêm một hàng

Tất cả đều hoạt động, ngoại trừ việc DataGridView hiển thị một hàng bổ sung, để thêm giá trị vào danh sách được liên kết. Hàng hiển thị nếu dataGridView.AllowUserToAddNewRows == true, đó là những gì tôi muốn. Những gì tôi không muốn là cho các ứng dụng sụp đổ khi hàng đó được chỉnh sửa theo chương trình; thay vào đó, nó nên làm chính xác những gì nó sẽ làm gì nếu người dùng đã chỉnh sửa hàng đó bằng tay (thêm hàng mới vào danh sách cơ bản, đẩy một hàng trống khác vào lưới để thêm giá trị).

Tôi đọc về SendKeys.Send(), điều này sẽ làm cho DataGridView hoạt động chính xác như thể người dùng đã nhập giá trị vào; tuy nhiên, nó cũng không hoạt động. Đây là những gì tôi đang cố gắng:

if (openFileDialog1.ShowDialog() == DialogResult.OK) 
{ 
    dataGridView1.CurrentCell = cell; 

    //simply doing a cell.Value = etc. will cause the program to crash 
    cell.ReadOnly = false; 
    dataGridView1.Columns[cell.ColumnIndex].ReadOnly = false; 
    dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter; 
    dataGridView1.BeginEdit(true); 
    SendKeys.Send(openFileDialog1.FileName + "{Enter}"); 
    dataGridView1.EndEdit(); 
    cell.ReadOnly = true; 
    dataGridView1.Columns[cell.ColumnIndex].ReadOnly = true; 
} 
//I would expect the FileName would be in the cell now, and a new empty 
//row tacked onto the end of the DataGridView, but it's not; the DataGridView 
//is not changed at all. 
+0

Loại ngoại lệ nào bạn nhận được khi bạn đặt 'cell.Value'? –

+0

@Zach: Khi tôi nhấp vào ô trống, nó sẽ điền vào giá trị chính xác nhưng không thêm hàng trống khác. Khi tôi nhấp chuột ra khỏi hàng, các giá trị trong tất cả các ô trên hàng cuối cùng biến mất (điều này chỉ xảy ra cho hàng cuối cùng đó). Khi tôi sau đó bấm vào hàng cuối cùng một lần nữa, tôi nhận được một InvalidOperationException: "Hoạt động không hợp lệ do trạng thái hiện tại của đối tượng." dataGridView1_CellClick là sự kiện duy nhất tôi đang xử lý trên biểu mẫu đó (được hiển thị ở trên) –

Trả lời

9

Tôi đã gặp vấn đề tương tự khi cố gắng chỉnh sửa các ô bằng chương trình với nguồn ràng buộc. "" Operation là không hợp lệ do tình trạng hiện thời của đối tượng"

nào hoạt động? Nhà nước gì? Vì vậy, hữu ích.

Mã của tôi dường như làm việc tốt, ngoại trừ khi chỉnh sửa hàng cuối cùng trong lưới.

Hóa ra chìa khóa được DataGridView.NotifiyCurrentCelldirty (true)

trình tự chính xác cho programatically chỉnh sửa một tế bào, vì vậy nó hoạt động giống như nếu người dùng đã làm nó. (một hàng trống mới xuất hiện khi thay đổi một tế bào ở hàng cuối cùng) giống như sau:

1) Làm cho tế bào để chỉnh sửa các tế bào hiện tại (làm những gì mà bạn cần đến currentcell hiện nay, đầu tiên như gọi EndEdit nếu nó đang trong chế độ chỉnh sửa.)

2) Gọi DataGridview.BeginEdit (false)

3) Gọi DataGridView.NotifyCurrentCellDirty (true)

4) Sửa đổi giá trị.

5) Gọi DataGridView.EndEdit()

Và bạn sẽ muốn làm điều gì đó cho các sự kiện RowValidating và RowValidated.

Một trong những thói quen của tôi để cập nhật một giá trị của ô trông như thế này:

Đây là từ một phương pháp trong lớp học của tôi bắt nguồn từ DataGridView. Bạn có thể làm điều tương tự từ biểu mẫu có chứa, gọi thông qua một cá thể DataGridView, vì các phương thức được công khai. Ở đây, các cuộc gọi đang sử dụng một thuật ngữ 'này'.

private void EnterTime() 
    { 
     if (CurrentRow == null) return; 

     SaveCurrentCell(); // Calls EndEdit() if CurrentCell.IsInEditMode 
     DataGridViewCell previous = CurrentCell; 

     CurrentCell = CurrentRow.Cells[CatchForm.TimeColumn]; 
     BeginEdit(false); 
     NotifyCurrentCellDirty(true); 
     CurrentCell.Value = DateTime.Now; 
     EndEdit(); 

     CurrentCell = previous; 

    } 

Tôi không chắc chắn tại sao cần có một cuộc gọi riêng biệt.

Tại sao không Bắt đầu chỉnh sửa hoặc thực sự sửa đổi giá trị ô, gây ra sự cố điều gì sẽ xảy ra?

Và nếu bạn di chuyển cuộc gọi NotifyCurrentCellDirty đến sau khi bạn thực sự sửa đổi ô, cũng không hoạt động chính xác. Tất cả rất khó chịu.

+0

Cảm ơn bạn đã dành thời gian để thêm điều này, Darrel. Tôi đã từ lâu quên lãng về vấn đề này, nhưng tôi sẽ đánh dấu điều này là chính xác, bởi vì tôi không biết tại sao workaround của tôi lại hoạt động. –

+0

Trong trường hợp của tôi, tôi cũng cần gọi CurrentCell.NotifyCurrentCellDirty (false) sau EndEdit() – synergetic

1

Hãy thử điều này:

 if (openFileDialog1.ShowDialog() == DialogResult.OK) 
     { 
      int row = e.RowIndex; 
      int clmn = e.ColumnIndex; 
      if(e.RowIndex == dataGridView1.Rows.Count- 1) 
       dataGridView1.Rows.Add(); 
      dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName; 
     } 

EDIT tôi đã không nhận thấy rằng bạn đang ràng buộc datagridview của bạn :( Ok, để giải quyết nó : sử dụng nguồn ràng buộc, đặt thuộc tính DataSource của nó vào danh sách của bạn, sau đó đặt nguồn dữ liệu của chế độ xem lưới dữ liệu thành nguồn ràng buộc này. Bây giờ, mã sẽ trông giống như sau:

public partial class frmTestDataGridView : Form 
    { 
     BindingSource bindingSource1 = new BindingSource(); 
     List<string> datasource = new List<string>(); 
     public frmTestDataGridView() 
     { 
      InitializeComponent(); 
      datasource.Add("item1"); 
      datasource.Add("item2"); 
      datasource.Add("item3"); 

      bindingSource1.DataSource = datasource; 
      dataGridView1.DataSource = bindingSource1; 
     } 

     private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) 
     { 
      if (openFileDialog1.ShowDialog() == DialogResult.OK) 
      { 
       int row = e.RowIndex; 
       int clmn = e.ColumnIndex; 

       if (e.RowIndex == dataGridView1.Rows.Count - 1) 
       { 
        bindingSource1.Add(""); 
       } 
       dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName; 
      } 
     } 

    } 
+0

"Hàng không thể được thêm theo chương trình vào bộ sưu tập hàng của DataGridView khi điều khiển bị ràng buộc dữ liệu". –

+0

Và nếu tôi cố gắng thêm vào BindingList thay vào đó, nó mang lại cho tôi cùng một "Thao tác không hợp lệ do trạng thái hiện tại của đối tượng" –

+0

Rất tiếc! Tôi đã không nhận thấy rằng bạn đang ràng buộc GridView vào một danh sách! Tôi đã cập nhật câu trả lời của mình ở trên. Vui lòng kiểm tra và cho chúng tôi biết kết quả. –

16

Tôi tìm thấy một workaround trên this page, mặc dù tôi không biết tại sao nó hoạt động

public MyForm() 
{ 
    InitializeComponent(); 
    //Create a BindingSource, set its DataSource to my list, 
    //set the DataGrid's DataSource to the BindindingSource... 
    _bindingSource.AddingNew += OnAddingNewToBindingSource; 
} 

private void OnAddingNewToBindingSource(object sender, AddingNewEventArgs e) 
{ 
    if(dataGridView1.Rows.Count == _bindingSource.Count) 
    { 
     _bindingSource.RemoveAt(_bindingSource.Count - 1); 
    } 
} 

tôi nhận được rất ốm chi tiêu rất nhiều thời gian đối phó với Visual Studio lỗi ...

+3

+1 cho câu hỏi và câu trả lời - cảm ơn, điều này chỉ hoạt động và giúp chúng tôi rất nhiều. –

+0

+1 Cảm ơn bạn !!! –

+0

+1 Cảm ơn bạn! điều này làm việc cho tôi = D – ch2o

3

Đây là cũ, nhưng tôi đang chạy VS2010 và chỉ gặp vấn đề này. Tôi có một số DataGridView được liên kết với một số List<T> bằng cách sử dụng BindingList<T>. Tôi có sự kiện kéo thả n 'trên DataGridView và nó sẽ ném ngoại lệ này sau khi xóa tất cả các hàng khỏi DGV (ngoại trừ một hàng trống cuối cùng không thể xóa) và rồi thêm hàng mới vào DGV Xử lý DragDrop qua số BindingList<T>. Ngoại lệ này không được ném nếu tôi chỉ cần thêm các hàng thủ công chỉnh sửa các ô riêng lẻ.

Một giải pháp mà tôi đọc cho biết để xử lý sự kiện BindingList<T>.AddNew, nhưng tôi nhận thấy sự kiện này không kích hoạt khi gọi BindingList<T>.Add() trong trình xử lý sự kiện DragDrop (Tôi không chắc chắn lý do). Tôi giải quyết vấn đề này bằng cách thêm

if(bindingList.Count == 0) 
    bindingList.RemoveAt(0) 

bên trong handler DragDrop kiện trước thêm các đối tượng mới để bindingList. Dường như việc thêm đối tượng vào số bindingList không thành công khi chỉ có "đối tượng" trong bindingList là đối tượng được liên kết với hàng trống cuối cùng. Điểm của BindingList<T> là cho phép nhà phát triển làm việc với nó thay vì của DGV trực tiếp, nhưng có vẻ như làm như vậy có thể gây ra sự cố trong trường hợp biên giới.

Mối quan hệ giữa các hàng DGV và BindingList<T> hàng dường như hơi có một khu vực màu xám. Tôi đã không dành nhiều thời gian điều tra này, nhưng nó không phải là rõ ràng cho tôi trạng thái của "đối tượng" trong BindingList<T> kết hợp với hàng cuối cùng (trống) của DGV là gì. Tuy nhiên, nó có vẻ như "đối tượng" ở cuối là chỉ instantiated "chính xác" khi bạn tương tác với hàng cuối cùng trực tiếp (không thông qua một DataSource).

+2

Tuyệt vời. Tôi đã có cùng một vấn đề. Tôi đã sử dụng 'if (DataGridView.Rows.Count == bindingList.Count) {bindingList.RemoveAt (source.Count - 1); } 'lúc bắt đầu trình xử lý thả và hoạt động. –

0

Hãy nhớ sử dụng Row.BeginEdit()Row.EndEdit() nếu bạn gặp lỗi này trong khi chỉnh sửa giá trị trong một hàng, sử dụng DataGrid hoặc GridEX từ Janus (trong trường hợp của tôi). Mã mẫu mà Darrel Lee đăng ở đây (https://stackoverflow.com/a/9143590/1278771) nhắc tôi sử dụng các hướng dẫn mà tôi đã quên sử dụng và điều này giải quyết được vấn đề cho tôi.

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