与工具提示相关的难以捉摸的 WPF 异常

Elusive WPF Exception related to ToolTip

我已经部署了我的(相当复杂且相当大)WPF 应用程序的一个版本,一些用户(不是所有用户)遇到以下异常。

FEHLER: Bei dem angegebenen Element handelt es sich bereits um das logische untergeordnete Element eines anderen Elements. Führen Sie zuerst eine Trennung durch.
   bei System.Windows.FrameworkElement.ChangeLogicalParent(DependencyObject newParent)
   bei MS.Internal.FrameworkObject.ChangeLogicalParent(DependencyObject newParent)
   bei System.Windows.FrameworkElement.AddLogicalChild(Object child)
   bei System.Windows.Controls.ContentControl.OnContentChanged(Object oldContent, Object newContent)
   bei System.Windows.Controls.ContentControl.OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   bei System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)
   bei System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, OperationType operationType, Boolean isInternal)
   bei System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   bei System.Windows.Data.BindingOperations.SetBinding(DependencyObject target, DependencyProperty dp, BindingBase binding)
   bei System.Windows.Controls.PopupControlService.RaiseToolTipOpeningEvent()
   bei System.Windows.Controls.PopupControlService.OnRaiseToolTipOpeningEvent(Object sender, EventArgs e)
   bei System.Windows.Threading.DispatcherTimer.FireTick(Object unused)
   bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)

异常消息的英文版本是:

Specified element is already the logical child of another element. Disconnect it first.

我的主要问题是, a) 我无法在我的开发机器上重现它。 这并不意味着它不会在相同的情况下发生,而是用户都独立地说异常发生在软件的特定时间点、操作或状态。

b) none 以上调用实际上是指我自己的代码。 所以我想它一定在 XAML

的某个地方

我完全迷路了,希望能得到一些大致方向的指示。

编辑:我现在能够重现并隔离问题

Demo Application

演示应用程序重现了一个异常,当 将复杂的工具提示(除了字符串对象之外的任何东西)放置在元素(按钮)上,而元素(按钮)又放置在弹出窗口上时会发生该异常。

<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <ToggleButton x:Name="_PopUpToggle" Content="Open Popup"/>
    <Popup 
        IsOpen="{Binding ElementName=_PopUpToggle,Path=IsChecked}" 
        Placement="Bottom"
        >
        <Grid Background="Wheat">
            <StackPanel 
                HorizontalAlignment="Center" 
                VerticalAlignment="Center">
                <Button 
                    Content="StackPanelToolTip"
                    Click="Button_Click">
                    <Button.ToolTip>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="Not "/>
                            <TextBlock Text="Plain"/>
                        </StackPanel>
                    </Button.ToolTip>
                </Button>
            </StackPanel>
        </Grid>
    </Popup>
</Grid>

要重现启动应用程序,请打开弹出窗口,将鼠标悬停在第一个按钮上,等待工具提示出现并单击。重复。这会产生以下带有相应 TraceStack 的异常:

Bei dem angegebenen Element handelt es sich bereits um das logische untergeordnete Element eines anderen Elements. Führen Sie zuerst eine Trennung durch.
   bei System.Windows.FrameworkElement.ChangeLogicalParent(DependencyObject newParent)
   bei System.Windows.FrameworkElement.AddLogicalChild(Object child)
   bei System.Windows.Controls.ContentControl.OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   bei System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)
   bei System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, OperationType operationType, Boolean isInternal)
   bei System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   bei System.Windows.Data.BindingOperations.SetBinding(DependencyObject target, DependencyProperty dp, BindingBase binding)
   bei System.Windows.Controls.PopupControlService.RaiseToolTipOpeningEvent()
   bei System.Windows.Threading.DispatcherTimer.FireTick(Object unused)
   bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   bei System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

异常消息的英文版本是:

Specified element is already the logical child of another element. Disconnect it first.

将工具提示绑定到普通字符串对象(尝试第二个按钮)确实可以正常工作。这是我目前的解决方法。

正如 Mathew 所指出的,在 <ToolTip></ToolTip> 中包含工具提示的复杂内容-属性 解决了这个问题。