Страницы: 1
RSS
VBA: конфликт стандартного окна замены и Worksheet_Change
 
Добрый день!

У меня на единственном листе событие 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
Изменено: RazorBaze - 23.08.2018 10:02:50
 
Как-то непонятно зачем менять, если ничего менять нельзя, не проще просто защитить лист, в чем суть?
 
Вы сами подошли к проблеме заметив четность и прочее. ваш код  зацикливался на изменениях то туда то сюда, и только ограничения сделанные разработчиком останавливали этот процесс. Соответвенно, не надо зацикливать и все будет работать.

Код
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
Изменено: БМВ - 16.08.2018 21:39:20
По вопросам из тем форума, личку не читаю.
 
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,
на случай следующего конфликта замены.

Я геморройщик?
Да.
 
RazorBaze Вы изобретаете велосипед, когда все на нем уже ездят.
 
skais675, А вы знаете почему устойчив велосипед, когда едет? А вот тут люди пытаются доказать , что устройство лишенное эффекта гироскопа тоже устойчиво. Вдруг изобретут другой велосипед. Не душите инициативу :-)
По вопросам из тем форума, личку не читаю.
 
БМВ, прошу прощения: события у меня конечно отключены в начале и включены в конце
- я так к этому уже привык, что просто не указал
(отредактировал первое сообщение).

Наверное так и воспользуюсь советом skais675, если мой вариант будет давать сбои.
Изменено: RazorBaze - 16.08.2018 21:56:51
 
а вот это Columns(zChange.Column) у вас какой смысл имеет?
По вопросам из тем форума, личку не читаю.
 
БМВ, если четно - просто побоялся слишком подробно расписать то,
каким образом отслеживаю изменения в колонке 1.

В реальности, там очень много скучных условий, типа:
- If Intersect(Columns(1), zChange) = Nothing ...
- Set zTarget = Union(...), и т.д.

Но к вопросу о возможности отслеживания факта использования пользователем окна замены оно отношения не имело,
так что я сократил))
Страницы: 1
Наверх