NullReferenceException使用Treeview和PropertyChanged

时间:2012-02-24 21:57:42

标签: wpf treeview nullreferenceexception propertychanged

在视图模型中更新绑定属性时,我收到NullReferenceException。这只发生在我在视图中使用treeview控件时。如果我用列表替换它,那么例外就会消失。

这是我的代码中调试器中断的地方:

PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

大约30次调用之后,通过许多PresentationFramework和WindowsBase程序集,实际上会发生异常:

PresentationFramework.dll!System.Windows.StyleHelper.EvaluateOldNewStates()

这是树视图:

<TreeView DockPanel.Dock="Bottom" ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}"
                  ItemTemplate="{StaticResource categoryTemplate}" SelectedItemChanged="TreeView_SelectedItemChanged"/>

如果我改用这个列表框,问题就会消失:

<ListBox DockPanel.Dock="Bottom" ItemsSource="{Binding ApplicationServers}" DisplayMemberPath="Name"
                     SelectedItem="{Binding SelectedApplicationServer}" Height="auto"/>

我不确定这会有所帮助,但这里有更新的属性:

public ObservableCollection<ApplicationServer> ApplicationServers
        {
            get { return this._applicationServers; }

            private set
            {
                this._applicationServers = value;
                this.NotifyPropertyChanged(() => this.ApplicationServers);
            }
        }

以下是更新该属性的调用:

this.ApplicationServers = new ObservableCollection<ApplicationServer>(ApplicationServerLogic.GetAll().ToList());

有没有人经历过这样的事情?我不知道是什么导致了这个问题,我很想使用列表框。实际上,我现在几乎不得不使用列表框。我怎么能解决这个问题呢?这可能是PresentationFramework程序集中的错误吗?

此外,这是我视图的代码隐藏,显示了项目更改事件的处理。

private void TreeView_SelectedItemChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<object> e)
        {
            ((ApplicationServerViewModel)DataContext).SelectedApplicationServer = e.NewValue as ApplicationServer;
        }

编辑:有人要求提供更多代码,所以这里是:

        <CollectionViewSource x:Key="cvs" Source="{Binding ApplicationServers}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="DeploymentEnvironment"/>
            </CollectionViewSource.GroupDescriptions>
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Name" Direction="Ascending"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>

        <!-- Our leaf nodes (server names) -->
        <DataTemplate x:Key="serverTemplate">
            <TextBlock Text="{Binding Path=Name}"/>
        </DataTemplate>

        <!-- Note: The Items path refers to the items in the CollectionViewSource group (our servers).
                   The Name path refers to the group name. -->
        <HierarchicalDataTemplate x:Key="categoryTemplate"
                                  ItemsSource="{Binding Path=Items}"
                                  ItemTemplate="{StaticResource serverTemplate}">
            <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
        </HierarchicalDataTemplate>

2 个答案:

答案 0 :(得分:1)

虽然它没有回答你案件的原因;一种方法是将项添加到集合实例,而不是通过setter更改实例。删除暴露的setter,只需根据需要添加项目,这将引发基础集合上的CollectionChanged事件,这将为您提供最终的目标。

        public ObservableCollection<ApplicationServer> ApplicationServers
        {
            get { return this._applicationServers; }
        }

        ApplicationServers.Add(...);

答案 1 :(得分:-1)

我知道这个问题很古老。


就我而言,我正在扩展TabControl,并为其添加了新功能。这些功能之一更改了SelectedIndex属性。

如果该属性连续多次更改,我将得到相同的异常。

此外,由于某种原因,我不得不将其中一个标签设置为IsSelected = true,否则应用程序在打开窗口时会崩溃,但有类似的例外情况:

▬ Message - 
    Object reference not set to an instance of an object.
○ Type - 
    System.NullReferenceException
▲ Source - 
    PresentationFramework
▼ TargetSite - 
    Void EvaluateOldNewStates(System.Windows.MultiTrigger, System.Windows.DependencyObject, System.Windows.DependencyProperty, System.Windows.DependencyPropertyChangedEventArgs, Int32, System.Windows.Style, System.Windows.FrameworkTemplate, Boolean ByRef, Boolean ByRef)
♠ StackTrace - 
   at System.Windows.StyleHelper.EvaluateOldNewStates(MultiTrigger multiTrigger, DependencyObject triggerContainer, DependencyProperty changedProperty, DependencyPropertyChangedEventArgs changedArgs, Int32 sourceChildIndex, Style style, FrameworkTemplate frameworkTemplate, Boolean& oldState, Boolean& newState)
   at System.Windows.StyleHelper.OnTriggerSourcePropertyInvalidated(Style ownerStyle, FrameworkTemplate frameworkTemplate, DependencyObject container, DependencyProperty dp, DependencyPropertyChangedEventArgs changedArgs, Boolean invalidateOnlyContainer, FrugalStructList`1& triggerSourceRecordFromChildIndex, FrugalMap& propertyTriggersWithActions, Int32 sourceChildIndex)
   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.SetCurrentValueInternal(DependencyProperty dp, Object value)
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.CreateDeltaSelectionChange(List`1 unselectedItems, List`1 selectedItems)
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(ItemInfo info, Boolean assumeInItemsCollection)
   at System.Windows.Controls.Primitives.Selector.OnSelectedIndexChanged(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.SetCurrentValueInternal(DependencyProperty dp, Object value)
   at System.Windows.Controls.TabControl.OnGeneratorStatusChanged(Object sender, EventArgs e)
   at System.EventHandler.Invoke(Object sender, EventArgs e)
   at System.Windows.Controls.ItemContainerGenerator.SetStatus(GeneratorStatus value)
   at System.Windows.Controls.ItemContainerGenerator.Generator.System.IDisposable.Dispose()
   at System.Windows.Controls.Panel.GenerateChildren()
   at System.Windows.Controls.Panel.EnsureGenerator()
   at System.Windows.Controls.Panel.get_InternalChildren()
   at System.Windows.Controls.StackPanel.StackMeasureHelper(IStackMeasure measureElement, IStackMeasureScrollData scrollData, Size constraint)
   at System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.Controls.ScrollContentPresenter.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
   at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
   at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Control.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
   at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Documents.AdornerDecorator.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Border.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Window.MeasureOverrideHelper(Size constraint)
   at System.Windows.Window.MeasureOverride(Size availableSize)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Interop.HwndSource.SetLayoutSize()
   at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
   at System.Windows.Window.SetRootVisual()
   at System.Windows.Window.SetRootVisualAndUpdateSTC()
   at System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)
   at System.Windows.Window.CreateSourceWindow(Boolean duringShow)
   at System.Windows.Window.ShowHelper(Object booleanBox)
   at System.Windows.Window.ShowDialog()
   at MyApp.App.App_Startup(Object sender, StartupEventArgs e) in C:\fakepath\App.xaml.cs:line 223
   at System.Windows.Application.OnStartup(StartupEventArgs e)
   at System.Windows.Application.<.ctor>b__1_0(Object unused)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
 

由于我正在处理该新控件的Style(在Themes\Generic.xaml内部),所以我开始删除该自定义样式的某些部分,直到它再次开始起作用。

我能够找到有问题的代码。我有两个MultiTrigger,里面有2个和3个Condition。每个MultiTrigger都有Enter/Exit Actions,内部有Storyboard

通过用MultiTrigger替换MultiDataTrigger并将内部的Condition设置为使用Binding而不是直接访问该属性,它再次开始工作。

从此:

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="IsSelected" Value="True"/>
        <Condition Property="DisplayAccent" Value="True"/>
    </MultiTrigger.Conditions>

    <MultiTrigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0:0:0:0.15" Storyboard.TargetName="SelectionBorder" Storyboard.TargetProperty="Opacity" To="1"/>
            </Storyboard>
        </BeginStoryboard>
    </MultiDataTrigger.EnterActions>
    <MultiDataTrigger.ExitActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0:0:0:0.15" Storyboard.TargetName="SelectionBorder" Storyboard.TargetProperty="Opacity"/>
            </Storyboard>
        </BeginStoryboard>
    </MultiTrigger.ExitActions>
</MultiTrigger>

对此:

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsSelected, FallbackValue=False}" Value="True"/>
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=DisplayAccent, FallbackValue=False}" Value="True"/>
    </MultiDataTrigger.Conditions>

    <MultiDataTrigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0:0:0:0.15" Storyboard.TargetName="SelectionBorder" Storyboard.TargetProperty="Opacity" To="1"/>
            </Storyboard>
        </BeginStoryboard>
    </MultiDataTrigger.EnterActions>
    <MultiDataTrigger.ExitActions>
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0:0:0:0.15" Storyboard.TargetName="SelectionBorder" Storyboard.TargetProperty="Opacity"/>
            </Storyboard>
        </BeginStoryboard>
    </MultiDataTrigger.ExitActions>
</MultiDataTrigger>