У меня на единственном листе событие Worksheet_Change примерно следующего содержания:
Код
Private Sub Worksheet_Change(ByVal zChange As Range)
Application.EnableEvents = False
If Columns(zChange.Column) = 1 _
Then
Application.Undo: Exit Sub
Else
End If
Application.EnableEvents = True
End Sub
- т.е., попытка изменения данных внутри колонки 1 приводит к отмене изменений. Так я защищаю ячейки с данными.
Было замечено, что если вызвать стандартное окно "Найти", и произвести замену - события Worksheet_Change начнут выполняться последовательно для ВСЕХ ячеек, которые подошли условию замены (для 3х ячеек - 3 отдельных события Worksheet_Change, подряд). Т.е., zChange.Count в таком случае ВСЕГДА = 1 - даже если "изменённых заменой" ячеек больше одной (!!!), что отличает данный случай Worksheet_Change от случая удаления\переноса строк, например, где zChange.Count был бы кратен 16384.
Проблема оказалась в том, что если "изменённых заменой" ячеек получится ЧЁТНОЕ число - чётное число раз подряд выполненный Application.Undo, в рамках каждого отдельного Worksheet_Change, приведёт к тому, что изменения НЕ будут отменены (из-за отмены "отмены" изменений).
И если в случае переноса\удаления строк, я бы мог видоизменить код следующим образом:
Код
Private Sub Worksheet_Change(ByVal zChange As Range)
Application.EnableEvents = False
If Columns(zChange.Column) = 1 _
And zChange.Count = 1 _ '<<< добавленное условие.
Then
Application.Undo: Exit Sub
Else
End If
Application.EnableEvents = True
End Sub
- позволяя, тем самым, переносить\удалять строки, то для окна замены это снова приведёт к озвученной проблеме.
И т.д., и т.п.
...Вопрос: есть ли способ узнать, воспользовался ли пользователь окном замены - ???
__________________________________________ Для решения проблемы достаточно "перевоткнуть" (в макросе!) любую ячейку на Листе, после Application.Undo: тогда история изменений документа обнулится, и следующую отмену выполнить не удастся!
А чтобы система не ругалась на невозможность отмены - перед отменой поместите On Error Resume Next.
Примерно в таком виде:
Код
Private Sub Worksheet_Change(ByVal zChange As Range)
Application.EnableEvents = False
On Error Resume Next
Application.Undo (внутри условий \ как угодно)
Cells(1, 1). Value = Cells(1, 1).Value
Application.EnableEvents = True
End Sub
Вы сами подошли к проблеме заметив четность и прочее. ваш код зацикливался на изменениях то туда то сюда, и только ограничения сделанные разработчиком останавливали этот процесс. Соответвенно, не надо зацикливать и все будет работать.
Код
Private Sub Worksheet_Change(ByVal zChange As Range)
If zChange.Column = 1 Then
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
Exit Sub
End If
End Sub
skais675, про защиту знаю мало - изучу отдельно, если вариантов больше нет.
Как вариант, воспользуюсь Worksheet_Calculate: оно выполняется ровно один раз, в конце любого количества Worksheet_Change.
Т.е., можно повесить перед Application.Undo какое-нибудь условие, например:
Код
Private Sub Worksheet_Change(ByVal zChange As Range)
If Columns(zChange.Column) = 1 _
And QCaseReplace = 0 _
Then
QCaseReplace = 1
Application.Undo: Exit Sub
Else
End If
End Sub
- а потом "обнулить" его внутри Worksheet_Calculate, на случай следующего конфликта замены.
skais675, А вы знаете почему устойчив велосипед, когда едет? А вот тут люди пытаются доказать , что устройство лишенное эффекта гироскопа тоже устойчиво. Вдруг изобретут другой велосипед. Не душите инициативу :-)
БМВ, прошу прощения: события у меня конечно отключены в начале и включены в конце - я так к этому уже привык, что просто не указал (отредактировал первое сообщение).
Наверное так и воспользуюсь советом skais675, если мой вариант будет давать сбои.