Member 12344083 Ответов: 3

Как я могу проверить данные, вводимые пользователем в текстовое поле в проигранном событие фокуса без потери фокуса событие неоднократно стреляли?


У меня есть приложение wpf, в котором пользователь вводит номер рабочего задания в текстовое поле. В случае потери фокуса текстового поля запрашивается база данных для проверки наличия номера рабочего задания. Если нет, то отображается окно сообщения и вызывается метод Focus() элемента управления textbox, чтобы сохранить фокус на этом текстовом поле.

Что на самом деле происходит, так это то, что событие потерянного фокуса срабатывает повторно

Вот xaml для элемента управления textbox:

TextBox x:Name="txtWONumber" IsReadOnly="False" Focusable="True" HorizontalAlignment="Left" Height="23" Margin="174,15,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.384,0.424" FocusManager.LostFocus="TxtWONumber_LostFocus"/>


Вот код обработчика событий:

private void TxtWONumber_LostFocus(object sender, RoutedEventArgs e)
		{

			string strWONumber = this.txtWONumber.Text;
			//MessageBox.Show("Work Order No: " + strWONumber);

			var qryWorkOrder =
			(from w in dataEntities.vwWOPatternCheckDatas	
			 where w.WONumber == strWONumber
			 orderby w.WONumber
			 select new { w.WONumber }).ToList();

			if (qryWorkOrder.Count() == 0)
			{
				MessageBox.Show("Work Order Number not found! Please enter a valid Work Order Number.");
				txtWONumber.Focus();
				txtWONumber.SelectAll();
			}
		}


Спасибо,

Брайан Миллер

Что я уже пробовал:

Я пробовал использовать событие LostFocus, а также FocusManager.Событие LostFocus и поведение одинаковы.

Я потратил несколько часов на поиск соответствующей информации в интернете. Кажется, ничто не решает эту ситуацию. Самое близкое, что я нашел, связано с двумя последовательными текстовыми полями в порядке табуляции, каждое из которых имеет событие потери фокуса.

Richard Deeming

NB: Вместо того чтобы подсчитывать все совпадения, чтобы определить, есть ли они, лучше использовать любое из них Any или All:

if (!dataEntities.vwWOPatternCheckDatas.Any(w => w.WONumber == strWONumber)) { ... }
// Or:
if (dataEntities.vwWOPatternCheckDatas.All(w => w.WONumber != strWONumber)) { ... }

3 Ответов

Рейтинг:
2

AnkushK1

Вместо использования LostFocus вы также можете подумать о создании и использовании DependencyProperty строкового типа в коде позади и привязать его 2-мя способами к свойству Text TextBox. Свойство зависимостей предоставляет событие обратного вызова, которое можно использовать для проверки текста. Обратитесь к ссылке ниже для получения подробной информации о его использовании

Учебник WPF | свойства зависимостей[^]


Рейтинг:
1

Gerry Schmitz

Я сталкивался с вашей ситуацией с разными языками.

"Следующее поле" получит "фокус", в то время как предыдущее поле "теряет фокус".

"Установка фокуса" в то время как "потеря фокуса" в событии "потерянный фокус" становится проблематичным из-за логики фокуса "следующее поле".

"Обходной путь" (в моем случае) состоял в том, чтобы ("просто") сохранить имя поля текущего поля, теряя фокус, и в то же время в следующем поле "получил фокус" выполнить вызов логики проверки "предыдущих полей". Если он действителен, то "примите Фокус" нового поля, иначе отклоните новый Фокус, после чего фокус остается на последнем поле (например, Windows Forms имеет свойство "Can focus").

Я еще не проверял WPF (потому что в наши дни я чаще провожу проверку на уровне записей, чем на уровне полей) для эквивалентного "can focus", но вы, вероятно, можете вернуть фокус в предыдущее поле (из следующего поля), используя оператор focus.

Обратите внимание, что если ваше "поле" находится в "конце вашей формы", вам все равно придется прибегнуть к проверке на уровне записей, потому что теперь вы можете вообще не терять фокус (при "сохранении").

(Да; звучит некрасиво, но такова жизнь, когда вы делаете то, что большинство людей не делают: проверка на полевом уровне).

Что касается проверки "рабочего заказа #": в этих случаях я обычно использую "список выбора", как это делает каждый крупный программный продукт. Никогда не бывает так много "открытых" рабочих заданий, что вы не можете запросить в базе данных список номеров рабочих заданий, которые могут быть "выскочили", когда пользователь попадает в это поле.


Member 12344083

Большое вам спасибо за ответ. Я внес изменения в код, чтобы отделить логику проверки и вызвать эту функцию из события got focus следующего элемента-списка.

Это работает, но есть несколько проблем с этим подходом.

1. код проверки будет выполняться каждый раз, когда это поле списка получает фокус, даже если это не происходит путем выхода из текстового поля, которое нуждается в проверке. Результатом будет ненужный запрос к базе данных.

2. пользователь может полностью пропустить список, щелкнув мышью на другом элементе управления. В этом случае обработчик got focus для списка никогда не будет запущен, и проверка не произойдет.

Рейтинг:
1

Dylvh

Я думаю, что это то, что происходит. Вы показываете сообщение, но сразу же снова фокусируетесь на текстовом поле. Теперь у вас открыто окно сообщения, и вы хотите нажать кнопку ОК, чтобы закрыть его, но затем текстовое поле снова теряет фокус.

Может быть, попробуйте следующее:

private void TxtWONumber_LostFocus(object sender, RoutedEventArgs e)
		{
                        if (checkNumber) // Should number be checked
                        {
                            checkNumber = false;
        			string strWONumber = this.txtWONumber.Text;
        			//MessageBox.Show("Work Order No: " + strWONumber);
    
        			var qryWorkOrder =
        			(from w in dataEntities.vwWOPatternCheckDatas	
        			 where w.WONumber == strWONumber
        			 orderby w.WONumber
        			 select new { w.WONumber }).ToList();
    
        			if (qryWorkOrder.Count() == 0)
        			{
        				if (MessageBox.Show("Work Order Number not found! Please enter a valid Work Order Number.") == DialogResult.OK)
                                        {
                                		txtWONumber.Focus();
                        			txtWONumber.SelectAll();
                                                checkNumber = true;
                                        }
        			}
                        }
                        
		}



Итак, у вас есть глобальный bool переменная checkNumber, которая имеет значение true, указывает на то, что вы хотите проверить номер заказа на выполнение работ. Как только он входит в Оператор if, вы устанавливаете его в false и возвращаете в true после нажатия кнопки ok в окне сообщения.


Member 12344083

Большое вам спасибо за ответ. Я должен был бы отметить в этом вопросе, что проблема фокусировки возникла даже с закомментированным кодом окна сообщения. Программа, по-видимому, зависает, и пошаговое выполнение кода показывает, что обработчик событий lost focus вызывается повторно.

Я попробовал предложенное вами изменение, и оно не повлияло на поведение. Я надеялся, что так и будет, поскольку ваше предложение было самым ясным и простым на сегодняшний день.

Dylvh

Пожалуйста. Я обновил решение и надеюсь, что оно поможет.