2015-03-02 1 views
3

У меня есть unbound. Пользователь вводит некоторый действительный текст и оставляет элемент управления. Затем пользователь возвращается к элементу управления и вводит неверный текст. Я хочу показать пользователю сообщение, затем откат значения элемента управления до его предыдущего состояния и держать фокус в этом контроле.Альтернатива SendKeys «{Esc}» для несвязанного текстового поля Undo

Я попытался следующие подходы, ни один из которых получает меня именно то, что я ищу:


ВАРИАНТ A: SendKeys

Private Sub MyTextBox_BeforeUpdate(Cancel As Integer) 
    Cancel = DataIsInvalid(Me.MyTextBox.Value) 
    If Cancel Then SendKeys "{Esc}" 
End Sub  

Это именно то, что я хочу , но я действительно хочу избежать использования SendKeys. Есть много проблем, которые приходят с использованием SendKeys: Vista+ compatibility, ключи отправляются в другое приложение, и т.д.


ВАРИАНТ B: Отменить метод контроля

Private Sub MyTextBox_BeforeUpdate(Cancel As Integer) 
    Cancel = DataIsInvalid(Me.MyTextBox.Value) 
    If Cancel Then Me.MyTextBox.Undo 
End Sub  

Это просто сломанный для (по крайней мере, с MS Access 2002/XP). Этот метод не восстанавливает значение MyTextBox для допустимого ввода. Тем не менее, это позволяет пользователю изменять фокус на новый элемент управления, оставляя недействительный ввод на месте в Me.MyTextBox! Невероятно !!!


ВАРИАНТ C: Отменить метод формы

Private Sub MyTextBox_BeforeUpdate(Cancel As Integer) 
    Cancel = DataIsInvalid(Me.MyTextBox.Value) 
    If Cancel Then Me.Form.Undo 
End Sub  

The Undo здесь абсолютно ничего не делает. Но, по крайней мере, он не нарушает код BeforeUpdate Cancel = True и позволяет недействительным данным стоять.


ВАРИАНТ D: Явное восстановить старое значение в BeforeUpdate случае

Private mPrevMyTextBoxValue As Variant 

Private Sub MyTextBox_AfterUpdate() 
    mPrevMyTextBoxValue = Me.MyTextBox.Value 
End Sub 
Private Sub MyTextBox_BeforeUpdate(Cancel As Integer) 
    Cancel = DataIsInvalid(Me.MyTextBox.Value) 
    If Cancel Then Me.MyTextBox.Value = mPrevMyTextBoxValue 
    'If Cancel Then Me.MyTextBox.Text = mPrevMyTextBoxValue 
End Sub  

пытается присвоить предыдущее значение либо .Value или .Text имущества в результате текстового поля в то же сообщение об ошибке:

Макрос или функция, установленная для свойства BeforeUpdate или ValidationRule для этого поля, является превентивной ting {Название программы} для сохранения данных в поле.


ВАРИАНТ E: Явное восстановить старое значение в AfterUpdate случае

Private mPrevMyTextBoxValue As Variant 

Private Sub MyTextBox_AfterUpdate() 
    If DataIsInvalid(Me.MyTextBox.Value) Then 
     Me.MyTextBox.Value = mPrevMyTextBoxValue 
     Me.MyTextBox.SetFocus 
    Else 
     mPrevMyTextBoxValue = Me.MyTextBox.Value 
    End If 
End Sub 

Это очень близко к желаемому поведению. К сожалению, невозможно сосредоточиться на элементе управления, потому что событие AfterUpdate запускается с до обрабатываются нажатия клавиш Enter или Enter или мыши.Поэтому, даже если мы попытаемся заставить фокус надлежащим образом контролировать (в соответствии с приведенным выше описанием .SetFocus), программа немедленно переключит фокус на выбранный пользователем элемент управления.


Мне кажется, что «правильный» способ сделать это, чтобы использовать .Undo метод контроля. Однако это не работает для несвязанных элементов управления. Это необъяснимый недостаток, особенно учитывая тот факт, что нажатие клавиши Escape выполняет эту функцию для несвязанного поля.

Есть ли лучший способ сделать это, или я должен просто придерживаться использования SendKeys?

+0

Автоматическое возвращение назад к предыдущему значению является палкой. Не могли бы вы оповестить пользователя, когда значение недействительно, сохраняя фокус в текстовом поле и позволяя пользователю выбирать между вводом нового допустимого значения или нажатием ESC для возврата к предыдущему значению? – HansUp

+0

Вариант D определенно был бы моим выбором, но, к сожалению, ответ Microsoft на это касается Sendkeys по адресу: http://support.microsoft.com/kb/128195 – Newd

+0

@HansUp: Это подход, который я обычно беру. В этом случае мне бы очень хотелось заставить предыдущее значение без вмешательства пользователя. – mwolfe02

ответ

1

После того, как вы перешли на страницу 3 на google, я решил просто повеселиться и посмотреть, что происходит при попытке вашего варианта E. Ниже приведен лучший способ обхода, который я смог использовать, чтобы сосредоточиться на «Stay» на текстовое поле.

Private mPrevMyTextBoxValue As Variant 

Private Sub Text0_AfterUpdate() 
    If Me.Text0.Value = 0 Then 
     Me.Text0.Value = mPrevMyTextBoxValue 
     Me.Text12.SetFocus 
     Me.Text0.SetFocus 
    Else 
     mPrevMyTextBoxValue = Me.Text0.Value 
    End If 
End Sub 

0 симулирует, что он не прошел проверку. Кажется, что если вы установите фокус на что-то еще, прежде чем устанавливать его обратно в текстовое поле, с которым вы работаете, оно останется там. У меня нет ответа, почему, к сожалению.

Редактировать: Я решил попробовать запрограммировать свою теорию о том, как это работает.

Private blnGoToNextControl as Boolean 

Private Function SetFocus(ctrl As control) 

    blnGoToNextControl = True 
    If ctrl.HasFocus = True Then 
    'Do nothing 
    Else 
     ctrl.HasFocus = True 
     blnGoToNextControl = False 
    End If 
End Function 

Это моя идея о том, как работает функция SetFocus. Итак, после запуска события AfterUpdate он проверит, должен ли флаг перейти к следующему элементу управления, и убедитесь, что он установлен в false и не переходит к следующему элементу управления.

Грубое кодирование, очевидно, но, надеюсь, это дает мою теорию?

+0

Ничего себе, это совсем не то, что я ожидал. – mwolfe02

+0

Любые мысли о том, почему это работает? Я знаю, что ты сказал, что у тебя нет ответа, но есть ли у тебя какие-то теории? – mwolfe02

+0

Моя теория заключается в том, что когда вы устанавливаете фокус, она проверяет, имеет ли этот контроль фокус. Если это произойдет, он просто пропустит запрос. Как только он пропускает запрос, флаг «Перейти к следующему порядку вкладок» остается установленным как true. После выполнения функции она переходит к следующей вкладке. Поэтому, когда вы уходите и возвращаетесь, он устанавливает флаг в false и удерживает его под контролем, на который вы только что сосредоточили внимание. Я понимаю, что это просто в основном читается как беспорядок слов, но, надеюсь, мое объяснение имеет смысл. – Newd

0

Если несвязанный, почему бы не использовать это событие AfterUpdate:

Private Sub MyTextBox_AfterUpdate() 
    If DataIsInvalid(Me!MyTextBox.Value) Then 
     Me!MyTextBox.Value = Null 
     Me!MyTextBox.SetFocus 
    End If 
End Sub 

или модифицировать другое решение:

Private Sub MyTextBox_AfterUpdate() 

    Static mPrevMyTextBoxValue As Variant 

    If IsEmpty(mPrevMyTextBoxValue) Then 
     mPrevMyTextBoxValue = Null 
    End If 

    If DataIsInvalid(Me!MyTextBox.Value) Then 
     Me!MyTextBox.Value = mPrevMyTextBoxValue 
     Me!MyTextBox.SetFocus 
    Else 
     mPrevMyTextBoxValue = Me!MyTextBox.Value 
    End If 
End Sub 

Попробуйте переместить фокус с текстового поля, а затем обратно:

 Me!MyTextBox.Value = mPrevMyTextBoxValue 
     Me!SomeOtherControl.SetFocus 
     Me!MyTextBox.SetFocus 

Что someothercontrol может быть крошечным почти скрытым текстовым полем.

+0

Это вопрос «Вариант Е» в моем вопросе. Это не сработает, потому что мы не можем заставить фокус вернуться к элементу управления MyTextBox. Это связано с тем, что MS Access обрабатывает связанные события и код в следующем порядке: пользователь нажимает Tab/Enter -> BeforeUpdate run -> AfterUpdate run -> focus переходит к следующему элементу управления. Проблема заключается в том, что Access устанавливает фокус на следующий элемент управления * после завершения процесса AfterUpdate. Поэтому, пока Access выполнит запрос SetFocus на элемент управления MyTextBox, он сразу же переключит фокус на другой элемент управления, запрошенный пользователем до AfterUpdate. Имеют смысл? – mwolfe02

Смежные вопросы