2

目前我正在尝试将IsOpena 的属性绑定ToolTip到我的后备视图模型的属性。此外,绑定模式设置为“OneWayToSource”。

Style是应用于 aTreeViewItem并包含ToolTip定义:

<Style TargetType="TreeViewItem">
    <Setter Property="ToolTip">
        <Setter.Value>
            <ToolTip IsOpen="{Binding IsToolTipOpen, Mode=OneWayToSource}">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding CurrentValue, StringFormat={}Value: {0}}"/>
                    <TextBlock Text="{Binding UnitName, StringFormat={}Unit: {0}}"
                               Visibility="{Binding HasUnit, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                </StackPanel>
            </ToolTip>
        </Setter.Value>
    </Setter>
</Style>

这是它绑定到的属性的代码:

public bool IsToolTipOpen
{
    get
    {
       return mIsToolTipOpen;
    }
    set
    {
        PegasusContext.Current.LogMessage( new PegasusMessage( string.Format( "IsTooltipOpen: {0}", value ), LogLevel.Debug ) );

        if( mIsToolTipOpen == value ) return;
        mIsToolTipOpen = value;

        if( mIsToolTipOpen )
        {
            BackingIO.BeginWatching();
        }
        else
        {
            BackingIO.StopWatching();
        }
    }
}

第一次打开 ToolTip时,它将调用IsToolTipOpen将其值设置为 的属性false。此外,当 ToolTip 关闭时,它会将 的值再次设置IsToolTipOpenfalse...。随后的每一次,该值都会按预期设置。打开第一个 ToolTip 后,它会在附加了 ToolTip 的其他项目上执行奇怪的行为。例如,它将IsToolTipOpen属性设置为true然后false几乎立即返回。以后每次ToolTip打开时,它都可以正常工作。

这是您可以在我的属性设置方法的第一行看到的日志记录代码的报告IsToolTipOpen(还有一些我手写的附加注释):

TreeViewItem A:
IsTooltipOpen: False <-- ToolTip Opened
IsTooltipOpen: False <-- ToolTip Closed
IsTooltipOpen: True  <-- ToolTip Opened
IsTooltipOpen: False <-- ToolTip Closed

TreeViewItem B:
IsTooltipOpen: True <-- ToolTip Open
IsTooltipOpen: False <-- ToolTip Open, occured at the same time as the previous entry.
IsTooltipOpen: False <-- ToolTip Closed
IsTooltipOpen: True <-- ToolTip Opened
IsTooltipOpen: False <-- ToolTip Closed

所以我很好奇是否有人知道发生了什么?和可能的解决方案?

4

2 回答 2

1

这让我很困惑,我忍不住戳了一会儿,试图了解发生了什么。我不完全确定我已经完全理解了,但我比开始时更进一步 =D

我以非常简单ToolTip的方式复制了您的行为Grid,我很好地查看了事件,但ToolTipService一无所获,然后开始使用 WPF Snoop(无从属关系)来检查应用程序首次启动时的情况DataContextToolTip

看起来,ToolTip没有DataContext。当你第一次打开它。 没有上下文

ToolTip继承了DataContext. 语境

所以我假设正在发生的事情(这是我朦胧的地方),当你第一次将鼠标悬停在 上时ToolTipDataContext还没有正确绑定,所以你的 get/set 不能正确触发;OneWayToSource您看到任何消息的原因是此处解释的绑定模式行为的结果: OneWayToSource Binding 在 .NET 4.0 中似乎已损坏。如果你选择TwoWay绑定,你会注意到ToolTip第一次完全没有打开,但是在后期绑定之后会正常工作DataContext

这样做的原因ToolTip是其实现方式的结果,并且可能会发生共享ToolTips它不在可视化树中

工具提示(以及其中的所有内容)不是可视化树的一部分 - 它与 Image 之间没有父子关系,而是属性值关系。

当实际显示工具提示时,WPF 会做一些特殊的工作来将可继承属性的值从放置目标传播到工具提示中,

所以,我认为这听起来很合理,但你真的可以做些什么吗?

好吧,有些人想将 绑定ToolTip到可视树上的东西,并且鉴于定位父对象面临的困难,出现了一些解决方法(我在寻找解决方案时遇到了这些: http://blogs.msdn。 com/b/tom_mathews/archive/2006/11/06/binding-a-tooltip-in-xaml.aspx 在用户控件中获取工具提示以显示数据绑定文本并保持打开状态

两者都依赖于 , 的一个简洁属性,该属性ToolTipPlacementTarget获取或设置相对于工具提示打开时定位的UIElement。MSDN

所以,总而言之,为了让IsOpen属性绑定并正确运行,我在我的模型中这样做了:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}" Background="#FF95CAFF" 
    >
<Grid>
    <TextBlock Text="{Binding Path=TestObject.Name}">
        <TextBlock.ToolTip>
            <ToolTip IsOpen="{Binding DataContext.TestObject.IsToolTipOpen}" 
                DataContext="{Binding Path=PlacementTarget,
                    RelativeSource={RelativeSource Self}}" >
                <StackPanel Orientation="Vertical">
                    <!-- Show me what the `DataContext` is -->
                    <TextBlock Text="{Binding Path=DataContext}" />
                </StackPanel>
            </ToolTip>
        </TextBlock.ToolTip>
    </TextBlock>
</Grid>

在程序加载时找到上下文。 快乐的语境

在这种情况下,DataContextis WpfApplication1.MainWindow,并且我绑定到我用于测试的属性,称为TestObject. 您可能需要稍微修改语法才能在模板中找到所需的 `DataContext 项(根据您的结构,按照您已经完成的方式可能会更容易)。

如果我说了什么严重不正确的事情,请告诉我。

于 2013-11-10T13:43:03.633 回答
1

看来这些事件正在按ToolTip课程的预期工作。所以我创建了一个附加属性来解决我遇到的问题。

我有一个附加属性来启用事件注册:

public static readonly DependencyProperty EnableWatchProperty = DependencyProperty.RegisterAttached(
        "EnableWatch",
        typeof( bool ),
        typeof( ToolTipFix ),
        new PropertyMetadata( default( bool ), OnEnableWatchPropertyChanged ) );

    private static void OnEnableWatchPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
    {
        var toolTip = d as ToolTip;
        if( toolTip == null ) return;

        var newValue = (bool) e.NewValue;

        if( newValue )
        {
            toolTip.Opened += OnTooltipOpened;
            toolTip.Closed += OnTooltipClosed;
        }
        else
        {
            toolTip.Opened -= OnTooltipOpened;
            toolTip.Closed -= OnTooltipClosed;
        }
    }

我还有一个可以绑定的附加属性,它指示当前状态ToolTip

public static readonly DependencyProperty IsOpenProperty = DependencyProperty.RegisterAttached(
        "IsOpen",
        typeof( bool ),
        typeof( ToolTipFix ),
        new PropertyMetadata( default( bool ) ) );

事件处理程序只是将IsOpen属性设置为truefalse取决于被调用的事件。

以下是我在 XAML 中使用附加属性的方式:

<ToolTip local:ToolTipFix.EnableWatch="True" 
         local:ToolTipFix.IsOpen="{Binding IsToolTipOpen, Mode=OneWayToSource}">
    ...
</ToolTip>

如果有人有其他解决方案或解决此问题的原因,我将不胜感激。

于 2013-11-01T15:00:38.977 回答