5

我是 WPF 的新手,过去我使用过 Windows 窗体。我在这里遇到一个问题,我希望有人向我解释。下面是一个非常简单的例子。

我有一个 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 未被用户代码处理
Message=Object 引用未设置为对象的实例。
Source=TestProject StackTrace: 在 TestProject.MainWindow.UseDefaultFoldersCB_Checked(Object sender, RoutedEventArgs e) 在 C:\Users\jc\Desktop\Test\TestProject\MainWindow.xaml.cs:line 611 at System.Windows.EventRoute.InvokeHandlersImpl(Object在 System.Windows.Controls.Primitives.ToggleButton.OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 在 System.Windows.DependencyObject.OnPropertyChanged 的​​ System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) (DependencyPropertyChangedEventArgs e) 在 System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) 在 System.Windows.DependencyObject。NotifyPropertyChange(DependencyPropertyChangedEventArgs args) 在 System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata 元数据, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember) System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value) 的对象值、PropertyMetadata 元数据、Boolean coerceWithDeferredReference、Boolean coerceWithCurrentValue、OperationType operationType、Boolean isInternal)属性,对象值)对象值)对象值)UpdateEffectiveValue(EntryIndex entryIndex,DependencyProperty dp,PropertyMetadata 元数据,EffectiveValueEntry oldEntry,EffectiveValueEntry&newEntry,布尔 coerceWithDeferredReference,布尔 coerceWithCurrentValue,OperationType operationType)在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,对象值,PropertyMetadata 元数据,布尔 coerceWithDeferredReference,布尔 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)UpdateEffectiveValue(EntryIndex entryIndex,DependencyProperty dp,PropertyMetadata 元数据,EffectiveValueEntry oldEntry,EffectiveValueEntry&newEntry,布尔 coerceWithDeferredReference,布尔 coerceWithCurrentValue,OperationType operationType)在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,对象值,PropertyMetadata 元数据,布尔 coerceWithDeferredReference,布尔 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)EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) 在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) 在 System.Windows.DependencyObject.SetValue (DependencyProperty dp,对象值)在 MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(对象实例,XamlMember 属性,对象值)EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) 在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) 在 System.Windows.DependencyObject.SetValue (DependencyProperty dp,对象值)在 MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(对象实例,XamlMember 属性,对象值)Boolean coerceWithDeferredReference、Boolean coerceWithCurrentValue、OperationType operationType、Boolean isInternal) 在 MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember property, Object value) 的 System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)Boolean coerceWithDeferredReference、Boolean coerceWithCurrentValue、OperationType operationType、Boolean isInternal) 在 MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember property, Object value) 的 System.Windows.DependencyObject.SetValue(DependencyProperty dp, 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.

4

4 回答 4

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;
    }
}
于 2011-06-13T09:29:18.120 回答
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;
      }
}
于 2011-06-13T09:08:42.597 回答
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).

于 2011-06-13T09:06:09.667 回答
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.

于 2011-06-13T09:01:41.990 回答