在视图模型中更新绑定属性时,我收到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>
答案 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>