WPF - NullReferenceException on isEnabled
Asked Answered
W

4

5

I'm new to WPF, in the past I've used Windows Forms. I'm having an issue here that I like someone to explain to me. The below is a really simple example.

I've got a XAML page on which I've got a single checkbox, a button, and a text field. The checkbox is checked by default.

When the checkbox is unchecked, I want to enable the button and the text field, e.g.

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" />

Stack Trace:

System.NullReferenceException was unhandled by user code
Message=Object reference not set to an instance of an object.
Source=TestProject StackTrace: at TestProject.MainWindow.UseDefaultFoldersCB_Checked(Object sender, RoutedEventArgs e) in C:\Users\jc\Desktop\Test\TestProject\MainWindow.xaml.cs:line 611 at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.Controls.Primitives.ToggleButton.OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value) at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember property, Object value)

When I launch the application from Visual Studio, I get a NullReferenceException on the above code. Why does this code execute when the application launches? I'd have thought it would only execute when the checkbox is checked/unchecked? Why the NullReferenceException?

Thanks.

Worlock answered 13/6, 2011 at 8:40 Comment(5)
Where exactly in the block of code does the exception occur?Galcha
if (StartDirLocationTB.IsEnabled == false) - If I add in the commented out 'MessageBox.Show..' - that displays also - my question is really why this code is executing when the application starts up. This seems to be a fundamental difference between WinForms/WPF.Worlock
Could also include the relevant bits of xaml?Mario
Why the -1, I thought my explanation was pretty clear??Worlock
It is. Seeing the downvote left me scratching my head too.Galcha
W
4

The Reason why you are receiving call on this Event Handler is because while initializing the Page , XAML pareser sees that an Event is attached to Checked attribute of the Checkbox(i.e. this event will be called when ever checkbox IsChecked property is true) thus it is calling the event at the time of loading itself.

I will suggest that you use Click event of the checkbox, so that you can have an event whenever checkbox state is changed.

So you XAML will be something Like this.

<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" />

and the Eventhandler code remains same as..

private void UseDefaultFoldersCB_Click(object sender, RoutedEventArgs e)
{
      //MessageBox.Show("");
      if (StartDirLocationTB.IsEnabled == false)
      {
           StartDirLocationTB.IsEnabled = true;
      }

      if (SelectStartLocationBtn.IsEnabled == false)
      {
            SelectStartLocationBtn.IsEnabled = true;
      }
}
Wilburwilburn answered 13/6, 2011 at 9:8 Comment(4)
This is not a good answer as it is hooking the wrong event, both for keyboard users and a lot of UI testing frameworks - use databinding or just check for null.Orthogonal
@Sumit, becouse the logic of the code is about "checkbox is unchecked" not about what the user is doing with the mouse.Orthogonal
@Ian : this Click event is of Checkbox if user clicks at any other place except Checkbox this event will not be fired right.. Infact this Event serves as Checkbox status change event, which will be fired at both times when checkbox is checked and unchecked. So both cases can be handled in single event, which I think i better than handling these two case in two different events of Checked and UnChecked.Wilburwilburn
@Wilburwilburn - @Ian is referring to what happens when user check/uncheck the checkbox using the keyboard. With your code, nothing happens.Suilmann
S
6

The answer is to stop coding as if you are in WinForms. Use Databinding instead. I found a nice sample for you here. If you still want to do it in event handlers, keep it in the 'Checked' event and just add null checks. If you use the Click event, keyboard shortcuts won't work. Null-checking sample:

private void UseDefaultFoldersCB_Checked(object sender, RoutedEventArgs e)
{
    if (StartDirLocationTB != null && StartDirLocationTB.IsEnabled == false)
    {
         StartDirLocationTB.IsEnabled = true;
    }

    if (SelectStartLocationBtn != null && SelectStartLocationBtn.IsEnabled == false)
    {
         SelectStartLocationBtn.IsEnabled = true;
    }
}
Suilmann answered 13/6, 2011 at 9:29 Comment(0)
W
4

The Reason why you are receiving call on this Event Handler is because while initializing the Page , XAML pareser sees that an Event is attached to Checked attribute of the Checkbox(i.e. this event will be called when ever checkbox IsChecked property is true) thus it is calling the event at the time of loading itself.

I will suggest that you use Click event of the checkbox, so that you can have an event whenever checkbox state is changed.

So you XAML will be something Like this.

<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" />

and the Eventhandler code remains same as..

private void UseDefaultFoldersCB_Click(object sender, RoutedEventArgs e)
{
      //MessageBox.Show("");
      if (StartDirLocationTB.IsEnabled == false)
      {
           StartDirLocationTB.IsEnabled = true;
      }

      if (SelectStartLocationBtn.IsEnabled == false)
      {
            SelectStartLocationBtn.IsEnabled = true;
      }
}
Wilburwilburn answered 13/6, 2011 at 9:8 Comment(4)
This is not a good answer as it is hooking the wrong event, both for keyboard users and a lot of UI testing frameworks - use databinding or just check for null.Orthogonal
@Sumit, becouse the logic of the code is about "checkbox is unchecked" not about what the user is doing with the mouse.Orthogonal
@Ian : this Click event is of Checkbox if user clicks at any other place except Checkbox this event will not be fired right.. Infact this Event serves as Checkbox status change event, which will be fired at both times when checkbox is checked and unchecked. So both cases can be handled in single event, which I think i better than handling these two case in two different events of Checked and UnChecked.Wilburwilburn
@Wilburwilburn - @Ian is referring to what happens when user check/uncheck the checkbox using the keyboard. With your code, nothing happens.Suilmann
G
3

Property setters in XAML will cause events related to those properties changing to be raised, as if they were set in code (more or less). I believe at the point the XAML parser sets the property via your IsChecked="True", the event handler fires - and at that point your other objects defined in XAML have not been instantiated.

(Incidentally this is one of those places where Silverlight and WPF tend to differ in details).

Giannini answered 13/6, 2011 at 9:6 Comment(0)
U
1

I do not think XAML parser in WPF guarantees the order in which different properties and event handlers will be attached. I think in your case first of all it attaches your UseDefaultFoldersCB_Checked handler and then sets IsChecked to true which fires an event.

You can expand your question a bit by providing call stack when exception occurs.

Upsweep answered 13/6, 2011 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.