#c# #wpf #isenabled
#c# #wpf #isenabled
Вопрос:
Я новичок в WPF, в прошлом я использовал Windows Forms. У меня возникла проблема, которую я хотел бы, чтобы кто-нибудь объяснил мне. Приведенный ниже действительно простой пример.
У меня есть страница XAML, на которой у меня есть один флажок, кнопка и текстовое поле. Флажок установлен по умолчанию.
Когда флажок снят, я хочу включить кнопку и текстовое поле, например
private void UseDefaultFoldersCB_Checked(object sender, RoutedEventArgs e)
{
//MessageBox.Show("");
if (StartDirLocationTB.IsEnabled == false)
{
StartDirLocationTB.IsEnabled = true;
}
if (SelectStartLocationBtn.IsEnabled == false)
{
SelectStartLocationBtn.IsEnabled = true;
}
}
XAML:
<CheckBox Content="Use Default Folders" IsChecked="True" Height="16" HorizontalAlignment="Left" Margin="10,14,0,0" Name="UseDefaultFoldersCB" VerticalAlignment="Top" Checked="UseDefaultFoldersCB_Checked" />
<TextBox Height="23" IsEnabled="False" HorizontalAlignment="Left" Margin="9,38,0,0" Name="StartDirLocationTB" VerticalAlignment="Top" Width="403" Background="WhiteSmoke" />
<Button Content="Select Start Folder" IsEnabled="False" Height="23" HorizontalAlignment="Right" Margin="0,38,6,0" Name="SelectStartLocationBtn" VerticalAlignment="Top" Width="139" />
Трассировка стека:
Исключение System.NullReferenceException не было обработано пользовательским кодом
Сообщение = Ссылка на объект не установлена для экземпляра объекта.
Источник= Трассировка стека TestProject: в TestProject.Главное окно.UseDefaultFoldersCB_Checked (отправитель объекта, RoutedEventArgs e) в C:UsersjcDesktopTestTestProjectMainWindow.xaml.cs:line 611 в системе.Windows.Маршрут события.InvokeHandlersImpl (источник объекта, аргументы RoutedEventArgs, логическое значение повторно вызывается) в системе.Windows.Пользовательский интерфейс.Поднимите Eventimpl (отправитель DependencyObject, аргументы RoutedEventArgs) в системе.Windows.Элементы управления.Примитивы.Кнопка переключения.OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) в системе.Windows.Объект зависимости.OnPropertyChanged(DependencyPropertyChangedEventArgs e) в системе.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) в системе.Windows.DependencyObject.NotifyPropertyChange(аргументы DependencyPropertyChangedEventArgs) в системе.Windows.Объект зависимости.Обновите эффективное значение (EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntryamp; newEntry, логическое принудительное значение с deferredreference, логическое принудительное значение с currentValue, operationType operationType) в системе.Windows.DependencyObject.SetValueCommon (DependencyProperty dp, значение объекта, метаданные PropertyMetadata, логическая принудительная ссылка с заданной ссылкой, логическая принудительная ссылка с текущим значением, operationType operationType, Логическая внутренняя) в системе.Windows.DependencyObject.setValue(DependencyProperty dp, значение объекта) в MS Internal.Xaml.Runtime.ClrObjectRuntime.setValue(объект inst, свойство XamlMember, значение объекта)
Когда я запускаю приложение из Visual Studio, я получаю исключение NullReferenceException в приведенном выше коде. Почему этот код выполняется при запуске приложения? Я бы подумал, что это будет выполняться только тогда, когда флажок установлен / снят? Почему исключение NullReferenceException?
Спасибо.
Комментарии:
1. Где именно в блоке кода возникает исключение?
2. если (StartDirLocationTB. IsEnabled == false) — Если я добавлю в закомментированное ‘MessageBox.Show ..’ — которое также отображается — мой вопрос в том, почему этот код выполняется при запуске приложения. Похоже, это фундаментальное различие между WinForms / WPF.
3. Может также включать соответствующие биты xaml?
4. Почему -1, я думал, мое объяснение было довольно ясным??
5. Это так. Увидев отрицательный результат, я тоже почесал голову.
Ответ №1:
Ответ заключается в том, чтобы прекратить кодирование, как если бы вы работали в WinForms. Вместо этого используйте привязку данных. Я нашел для вас хороший образец здесь. Если вы все еще хотите сделать это в обработчиках событий, сохраните это в событии ‘Checked’ и просто добавьте нулевые проверки. Если вы используете событие Click, сочетания клавиш не будут работать. Пример проверки на нуль:
private void UseDefaultFoldersCB_Checked(object sender, RoutedEventArgs e)
{
if (StartDirLocationTB != null amp;amp; StartDirLocationTB.IsEnabled == false)
{
StartDirLocationTB.IsEnabled = true;
}
if (SelectStartLocationBtn != null amp;amp; SelectStartLocationBtn.IsEnabled == false)
{
SelectStartLocationBtn.IsEnabled = true;
}
}
Ответ №2:
Причина, по которой вы получаете вызов этого обработчика событий, заключается в том, что при инициализации страницы XAML pareser видит, что событие прикреплено к атрибуту Checked флажка (т. Е. Это событие будет вызвано, когда любое свойство checkbox IsChecked имеет значение true), таким образом, оно вызывает событие во время самой загрузки.
Я предлагаю вам использовать событие щелчка флажка, чтобы вы могли получать событие всякий раз, когда изменяется состояние флажка.
Таким образом, ваш XAML будет примерно таким.
<CheckBox Content="Use Default Folders" IsChecked="True" Height="16" HorizontalAlignment="Left" Margin="10,14,0,0" Name="UseDefaultFoldersCB" VerticalAlignment="Top" Click="UseDefaultFoldersCB_Click" />
<TextBox Height="23" IsEnabled="False" HorizontalAlignment="Left" Margin="9,38,0,0" Name="StartDirLocationTB" VerticalAlignment="Top" Width="403" Background="WhiteSmoke" />
<Button Content="Select Start Folder" IsEnabled="False" Height="23" HorizontalAlignment="Right" Margin="0,38,6,0" Name="SelectStartLocationBtn" VerticalAlignment="Top" Width="139" />
и код обработчика событий остается таким же, как..
private void UseDefaultFoldersCB_Click(object sender, RoutedEventArgs e)
{
//MessageBox.Show("");
if (StartDirLocationTB.IsEnabled == false)
{
StartDirLocationTB.IsEnabled = true;
}
if (SelectStartLocationBtn.IsEnabled == false)
{
SelectStartLocationBtn.IsEnabled = true;
}
}
Комментарии:
1. Это не очень хороший ответ, поскольку он перехватывает неправильное событие, как для пользователей клавиатуры, так и для многих фреймворков тестирования пользовательского интерфейса — используйте привязку данных или просто проверьте значение null.
2. @Sumit, потому что логика кода заключается в том, что «флажок снят», а не в том, что пользователь делает с помощью мыши.
3. @Ian: это событие щелчка имеет флажок, если пользователь нажимает в любом другом месте, кроме флажка, это событие не будет запущено правильно.. Фактически это событие служит событием изменения статуса флажка, которое будет запускаться оба раза, когда флажок установлен и когда флажок снят. Таким образом, оба случая могут быть обработаны в одном событии, что, я думаю, лучше, чем обрабатывать эти два случая в двух разных событиях Checked и UnChecked.
4. @Sumit — @Ian ссылается на то, что происходит, когда пользователь устанавливает / снимает флажок с помощью клавиатуры. С вашим кодом ничего не происходит.
Ответ №3:
Установщики свойств в XAML вызовут события, связанные с изменением этих свойств, как если бы они были установлены в коде (более или менее). Я полагаю, что в тот момент, когда анализатор XAML устанавливает свойство через ваш IsChecked = «True», срабатывает обработчик событий — и в этот момент другие ваши объекты, определенные в XAML, не были созданы.
(Кстати, это одно из тех мест, где Silverlight и WPF, как правило, отличаются в деталях).
Ответ №4:
Я не думаю, что анализатор XAML в WPF гарантирует порядок, в котором будут подключены различные свойства и обработчики событий. Я думаю, что в вашем случае сначала он присоединяет ваш UseDefaultFoldersCB_Checked
обработчик, а затем устанавливает IsChecked
значение true, которое запускает событие.
Вы можете немного расширить свой вопрос, предоставив стек вызовов при возникновении исключения.