2010-08-25 37 views
7

Tôi có sổ làm việc Excel chứa một số điều khiển ComboBox được đặt trực tiếp trên trang tính. Đây là các hộp kết hợp tiêu chuẩn từ thanh công cụ Biểu mẫu.Excel VBA: Lưu thành trình kích hoạt Thay đổi sự kiện trong ComboBox

Khi người dùng sử dụng "Lưu dưới dạng" để lưu sổ làm việc có tên khác, điều này kích hoạt sự kiện Thay đổi trên tất cả các hộp tổ hợp, bao gồm cả sự kiện trên trang tính không hoạt động. Điều này có vẻ không hợp lý vì lựa chọn không thực sự thay đổi. Điều này gây ra nhiều hành vi không mong muốn vì mã trong trình xử lý sự kiện. Sự kiện không được kích hoạt trên "Lưu" đơn giản.

Google suggests đây là sự cố đã biết trong Excel. Có rumours rằng nó gây ra bằng cách sử dụng một phạm vi được đặt tên như ListFillRange cho hộp kết hợp, mà tôi đã làm, mặc dù nó không phải là một tên dễ bay hơi. Tôi đang tìm cách ngăn chặn điều này xảy ra với những thay đổi tối thiểu đối với mã và bảng tính. Có ai có một giải pháp đã được chứng minh?

+3

Tôi không thể tạo lại hành vi này bằng Excel 2007, không sử dụng phạm vi bình thường hoặc không sử dụng dải ô được đặt tên. Có lẽ bạn nên tải lên một ví dụ ... –

+0

@belisarius Tôi không thể tải lên sổ làm việc đầy đủ vì nó chứa rất nhiều mã độc quyền. Tôi không có thời gian để cố gắng tạo ra một ví dụ nhỏ: ( – MarkJ

+1

Không thể xác nhận trong Excel 2003. Bạn có thể xác nhận rằng bạn đang sử dụng điều khiển "Biểu mẫu" chứ không phải điều khiển "erm", "Điều khiển" không? (Điều khiển biểu mẫu không có sự kiện 'Thay đổi' hoặc các thuộc tính như' ListFillRange'. – Lunatik

Trả lời

2

Bạn có thể đặt cờ trong sự kiện BeforeSave của Sổ làm việc và sau đó kiểm tra cờ đó trước khi xử lý sự kiện thay đổi trong mỗi hộp tổ hợp. Có vẻ như không phải là một sự kiện AfterSave, vì vậy bạn sẽ cần phải xóa cờ sau khi kiểm tra nó trong các sự kiện thay đổi hộp combo. Cờ sẽ cần phải nhiều hơn một boolean đơn giản vì nó không thể được tắt cho đến khi tất cả các sự kiện thay đổi hộp combo được xử lý. Dưới đây là một số mã mẫu:

Public ComboBoxChangeCounter As Integer 

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) 
    Const NumOfComboBoxChangeEvents As Integer = 5 
    ComboBoxChangeCounter = NumOfComboBoxChangeEvents 
End Sub 

Function JustSaved() As Boolean 
    If ComboBoxChangeCounter > 0 Then 
     ComboBoxChangeCounter = ComboBoxChangeCounter - 1 
     JustSaved = True 
    End If 
End Function 

Private Sub Combo1_Change() 
    If JustSaved Then Exit Sub 
    'Your existing code ' 
    ' ... ' 
    ' ... ' 
    ' ... ' 
End Sub 

Tôi đặt số lượng sự kiện thay đổi hộp kết hợp thành hằng số, nhưng có thể có một số cách để bạn xác định số đó theo chương trình. Cách giải quyết này yêu cầu thêm mã vào mỗi sự kiện thay đổi hộp kết hợp, nhưng nó phải dễ dàng như tất cả những gì bạn cần làm là sao chép và dán dòng If JustSaved Then Exit Sub vào đầu mỗi sự kiện.

Cách giải quyết này giả định rằng sự kiện Workbook BeforeSave sẽ được gọi trước sự kiện thay đổi hộp kết hợp. Tôi không biết thực tế nếu đó là trường hợp.

+0

Đây không phải là một ý tưởng tồi, nhưng điều đó có nghĩa là bạn phải biết số lượng các OLEObject sẽ ném một thay đổi Ngoài ra, việc bạn sử dụng một Const là không chính thống, một hằng số không nên thay đổi, giải pháp này dựa trên một tính năng không có giấy tờ của mã lỗi. _bona fide_ sự kiện sẽ bị bỏ qua. – adamleerich

3

Tôi đã làm như sau trong sổ làm việc mới chỉ với một trang tính, Sheet1, và nó dường như hoạt động với các sự kiện có thể xảy ra trước khi lưu và sau đó có thể bật lại chúng sau đó. Nó sẽ bỏ qua vấn đề bạn thấy bằng cách bắt chước sự kiện AfterSave. Đây là mã sự kiện của tôi trên Sheet1 (có thể là mã OLEObject, quá)

Option Explicit 

Private Sub Worksheet_Change(ByVal Target As Range) 
    MsgBox Target.Address & ": " & Target.Value 
End Sub 

Đây là mã ThisWorkbook tôi

Option Explicit 

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) 

    ' To see the change code work before disabling 
    ' Should show a message box 
    Sheet1.Range("A1") = "Before After Events Off" 

    Application.EnableEvents = False 
    Application.OnTime Now, "ThisWorkbook.Workbook_AfterSave" 

    ' This time it will not show a message box 
    ' You will never see this one . . . 
    Sheet1.Range("A1") = "After After Events Off" 

End Sub 

Private Sub Workbook_AfterSave() 
    Application.EnableEvents = True 
End Sub 

Phương pháp .OnTime ném "sự kiện" AfterSave vào hàng đợi thực hiện. Nó hoạt động!

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