为什么这个WPF TreeViewItem样式导致交叉线程问题?

时间:2018-02-02 09:44:44

标签: c# wpf

我将以下样式应用于treeviewitem容器。 基本上,用于覆盖选择颜色:

<Style x:Key="element-designer-node-host" TargetType="{x:Type TreeViewItem}">
    <Style.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" 
                         Color="{DynamicResource nav-tvi-sel-bg1}" />
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
                         Color="{DynamicResource nav-tvi-sel-bg1}" />
        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" 
                         Color="{DynamicResource nav-tvi-sel-bg2}" />
    </Style.Resources>
    <Setter Property="IsExpanded" Value="{Binding Expanded, Mode=TwoWay}" />
    <Setter Property="IsSelected" Value="{Binding Selected, Mode=TwoWay}" />
</Style>

应用于树视图:

<TreeView
    ItemContainerStyle="{StaticResource element-designer-node-host}"
    ItemsSource="{Binding Nodes}">

现在,我在一个新线程中启动一个带有此树视图的窗口,一切正常。

在该窗口关闭后,我在一个全新的线程中启动全新的窗口,当我尝试点击某个节点时,我得到了异常:

  

调用线程无法访问此对象,因为其他线程拥有该对象。

     

在System.Windows.Threading.Dispatcher.VerifyAccess()处   System.Windows.Freezable.System.Windows.ISealable.get_IsSealed()at   System.Windows.StyleHelper.SealIfSealable(Object value)at   System.Windows.StyleHelper.GetChildValueHelper(UncommonField 1 dataField, ItemStructList 1&amp; valueLookupList,DependencyProperty dp,   DependencyObject容器,FrameworkObject子,Int32 childIndex,   Boolean styleLookup,EffectiveValueEntry&amp; entry,ValueLookupType&amp;   sourceType,FrameworkElementFactory templateRoot)at   System.Windows.StyleHelper.GetChildValue(UncommonField 1 dataField, DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList 1&amp; childRecordFromChildIndex,   EffectiveValueEntry&安培; entry,ValueLookupType&amp; sourceType的,   FrameworkElementFactory templateRoot)at   System.Windows.StyleHelper.GetValueFromTemplatedParent(DependencyObject的   容器,Int32 childIndex,FrameworkObject子项,DependencyProperty   dp,FrugalStructList 1& childRecordFromChildIndex, FrameworkElementFactory templateRoot, EffectiveValueEntry& entry)
at System.Windows.FrameworkElement.GetValueFromTemplatedParent(DependencyProperty dp, EffectiveValueEntry& entry) at System.Windows.FrameworkElement.GetRawValue(DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry& entry) at System.Windows.FrameworkElement.EvaluateBaseValueCore(DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry& newEntry) at System.Windows.DependencyObject.EvaluateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry newEntry, OperationType operationType) 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.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue) at System.Windows.StyleHelper.InvalidateDependents(Style ownerStyle, FrameworkTemplate frameworkTemplate, DependencyObject container, DependencyProperty dp, FrugalStructList
1&amp; dependents,布尔   invalidateOnlyContainer)at   System.Windows.StyleHelper.OnTriggerSourcePropertyInvalidated(风格   ownerStyle,FrameworkTemplate frameworkTemplate,DependencyObject   container,DependencyProperty dp,DependencyPropertyChangedEventArgs   changedArgs,Boolean invalidateOnlyContainer,FrugalStructList`1&amp;   triggerSourceRecordFromChildIndex,FrugalMap&amp;   propertyTriggersWithActions,Int32 sourceChildIndex)at   System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs   吃   System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs   args)at   System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex   entryIndex,DependencyProperty dp,PropertyMetadata元数据,   EffectiveValueEntry oldEntry,EffectiveValueEntry&amp; newEntry,布尔值   coerceWithDeferredReference,Boolean coerceWithCurrentValue,   OperationType operationType)at   System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,   对象值,PropertyMetadata元数据,布尔值   coerceWithDeferredReference,Boolean coerceWithCurrentValue,   OperationType operationType,Boolean isInternal)at   System.Windows.DependencyObject.SetValue(DependencyProperty dp,Object   System.Windows.Controls.TreeView.ChangeSelection(Object。)   data,TreeViewItem容器,布尔选中)at   System.Windows.Controls.TreeViewItem.Select(布尔选中)at   System.Windows.Controls.TreeViewItem.OnGotFocus(RoutedEventArgs e)
  在System.Windows.UIElement.IsFocused_Changed(DependencyObject d,   DependencyPropertyChangedEventArgs e)at   System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs   吃   System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs   吃   System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs   args)at   System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex   entryIndex,DependencyProperty dp,PropertyMetadata元数据,   EffectiveValueEntry oldEntry,EffectiveValueEntry&amp; newEntry,布尔值   coerceWithDeferredReference,Boolean coerceWithCurrentValue,   OperationType operationType)at   System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,   对象值,PropertyMetadata元数据,布尔值   coerceWithDeferredReference,Boolean coerceWithCurrentValue,   OperationType operationType,Boolean isInternal)at   System.Windows.DependencyObject.SetValue(DependencyPropertyKey key,   对象值)   System.Windows.Input.FocusManager.OnFocusedElementChanged(DependencyObject的   d,DependencyPropertyChangedEventArgs e)at   System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs   吃   System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs   吃   System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs   args)at   System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex   entryIndex,DependencyProperty dp,PropertyMetadata元数据,   EffectiveValueEntry oldEntry,EffectiveValueEntry&amp; newEntry,布尔值   coerceWithDeferredReference,Boolean coerceWithCurrentValue,   OperationType operationType)at   System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,   对象值,PropertyMetadata元数据,布尔值   coerceWithDeferredReference,Boolean coerceWithCurrentValue,   OperationType operationType,Boolean isInternal)at   System.Windows.Input.FocusManager.SetFocusedElement(DependencyObject的   element,IInputElement value)at   System.Windows.Input.KeyboardNavigation.UpdateFocusedElement(DependencyObject的   focusTarget)at   System.Windows.FrameworkElement.OnGotKeyboardFocus(Object sender,   KeyboardFocusChangedEventArgs e)at   System.Windows.Input.KeyboardFocusChangedEventArgs.InvokeEventHandler(代表   genericHandler,Object genericTarget)at   System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象   目标)   System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target,   RoutedEventArgs routedEventArgs)at   System.Windows.EventRoute.InvokeHandlersImpl(Object source,   RoutedEventArgs args,Boolean reRaised)at   System.Windows.UIElement.RaiseEventImpl(DependencyObject sender,   RoutedEventArgs args)at   System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)at at   System.Windows.UIElement.RaiseEvent(RoutedEventArgs args,Boolean   可信的)在System.Windows.Input.InputManager.ProcessStagingArea()   在System.Windows.Input.InputManager.ProcessInput(InputEventArgs   输入)   System.Windows.Input.KeyboardDevice.ChangeFocus(DependencyObject的   焦点,Int32时间戳)   System.Windows.Input.KeyboardDevice.TryChangeFocus(DependencyObject的   newFocus,IKeyboardInputProvider keyboardInputProvider,Boolean   askOld,Boolean askNew,Boolean forceToNullIfFailed)at   System.Windows.Input.KeyboardDevice.Focus(DependencyObject焦点,   Boolean askOld,Boolean askNew,Boolean forceToNullIfFailed)at   System.Windows.Input.KeyboardDevice.Focus(IInputElement element)at   System.Windows.UIElement.Focus()at   System.Windows.Controls.TreeViewItem.OnMouseLeftButtonDown(MouseButtonEventArgs   e)在System.Windows.UIElement.OnMouseLeftButtonDownThunk(Object   sender,MouseButtonEventArgs e)at   System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(代表   genericHandler,Object genericTarget)at   System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象   目标)   System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target,   RoutedEventArgs routedEventArgs)at   System.Windows.EventRoute.InvokeHandlersImpl(Object source,   RoutedEventArgs args,Boolean reRaised)at   System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender,   RoutedEventArgs args,RoutedEvent newEvent)at   System.Windows.UIElement.OnMouseDownThunk(Object sender,   MouseButtonEventArgs e)...

为什么会发生这种情况,解决方案是什么?

请注意,当我从样式资源中删除这三个笔刷覆盖时,不会出现此问题。

1 个答案:

答案 0 :(得分:2)

似乎样式的实际引用保留在element-designer-node-host的内存中。这使得引用的所有者成为已被销毁的线程。 https://datatables.net/examples/api/show_hide.html
这可能与第一次使用这些资源的新线程有关,但是没有看到更多的代码,这更像是猜测。
解决方案是要么在UI线程上创建新的Window,要么使用x:Shared="false",然后使用新创建的引用而不是使用共享引用。请记住,这会增加应用程序的内存占用,如果目标计算机的可用内存有限,则会导致内存不足。 来自More info from MSDN的更多信息。