WPF工具提示不会更新

时间:2011-07-11 03:04:34

标签: c# .net wpf binding

假设我有一个代表工作人员的简单课程

class Staff
{
    public string FirstName { get; set; }
    public string FamilyName { get; set; }
    public int SecondsAlive { get; set; }        
}

我有一个DataTemplate for staff

<DataTemplate DataType={x:Type Staff}>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text={Binding FirstName}/>
        <TextBlock Text=" ">
        <TextBlock Text={Binding FamilyName}/>
        <StackPanel.ToolTip>
            <TextBlock Text={Binding SecondsAlive}/>
        </StackPanel.ToolTip>
     </StackPanel>
</DataTemplate>

然后我在ListBox中展示了一大堆人员

myListBox.ItemsSource = GetAllStaff();

非常标准的东西。我遇到的问题是显示某人活着的秒数的工具提示没有得到更新。当你第一次将鼠标悬停在一名工作人员身上时,它可以正常工作,但从那时起它就永远保持这个价值。我可以实现INotifyPropertyChanged来解决这个问题,但是每当SecondsAlive发生变化时,每个工作人员都可以做到这一点。假设我在列表中有400名员工,那么我必须筹集400个事件,即使用户可能永远不会查看另一个工具提示。我想要的是使工具提示请求显示SecondsAlive属性。这可能吗?

请注意,这只是一个例子,我不需要知道我的员工活了多少秒:-)但我有同样的问题,我需要提高一个甚至大约400次的工具提示哪个人可能不会看。

5 个答案:

答案 0 :(得分:29)

OMG !!!我终于找到了解决这个问题的方法!这几个月一直困扰着我。我并不感到惊讶,没有人回答这个,因为我在顶部输入的代码实际上并没有显示我试图重现的问题,实际上它显示了解决方案。答案是,如果您像这样定义工具提示

    <StackPanel.ToolTip>
        <TextBlock Text={Binding SecondsAlive}/>
    </StackPanel.ToolTip>

然后一切正常,花花公子并且没有必要在“SecondsAlive”上引发propertyChanged事件。每次显示工具提示时,框架都会调用SecondsAlive属性。当您定义工具提示时会出现问题:

    <StackPanel.ToolTip>
        <ToolTip>
            <TextBlock Text={Binding SecondsAlive}/>
        <ToolTip>
    </StackPanel.ToolTip>

在那里有额外的工具提示标记是有道理的,当然你需要创建一个工具提示对象来将它分配给tooltip属性,但这是不正确的。您分配给tooltip属性的实际上是工具提示的内容。我假设您需要为其显示文本块和图像等控件,但您可以传入任何内容,它将像内容控件一样显示内容。看到它继承自内容控制这是有道理的:-)一旦你知道这一切似乎很明显: - )

感谢大家的关注。

PS。我发现了一个额外的问题,即简化代码的下一个逻辑步骤是将文本直接分配给工具提示,如下所示(假设您的工具提示是纯文本):

 <TextBlock Text="{Binding Path=StaffName}" ToolTip={Binding Path=StaffToolTip}/>

这也导致我遇到的原始问题。这是有道理的,因为属性StaffToolTip的结果被分配给tooltip属性,永远不会再被调用。但是,为什么然后将一个TextBlock分配给tooltip属性实际上解决了这个问题并不是很有意义。

答案 1 :(得分:1)

在这种特殊情况下,你可以使用一个很酷的技巧

Seconds Alive Now = Seconds Alive最初+ Elapsed Time

您可以绑定到Elapsed Time属性并指定一个向其添加初始值的转换器。这样你只需要引发1个事件,工具提示就会全部更新。

编辑:您可以将ElapsedTime属性(使用INotifyPropertyChanged)添加到许多位置 - 一个逻辑位置可以存储到您的Staff对象的集合

编辑:您还需要将每个工具提示绑定到共享的ElapsedTime属性而不是SecondsAlive属性

答案 2 :(得分:0)

值得注意的是,在使用新数据重新加载自己之前,工具提示似乎会检查您的对象是否已被绑定。

在我的情况下,我覆盖了

public override bool Equals(object obj) 

public override int GetHashCode()

在具有属性的类

public class MultipleNameObject { string Name, string[] OtherNames};

Unfortunatley我只在MultipleNameObject的Name属性上执行了string.Compare()以达到相等的目的。工具提示应该在ItemsControl中显示OtherNames,但是如果在鼠标悬停在网格上的前一个MultipleNameObject上名称相等,则不会更新,即使OtherNames不同。

[edit]在启用调试的情况下运行确认ToolTip正在使用我的对象的GetHashCode()重写来决定是否重新获取新数据。修复将字符串[] OtherNames考虑在内的问题解决了这个问题。

答案 3 :(得分:0)

此示例显示如何在网格中添加工具提示,以便在用户将鼠标悬停在网格中的单元格上时按需重新计算工具提示。

如果您有一个包含10,000个项目的巨大网格,并且您想要连续更新网格,但是您不想连续更新工具提示,这很有用。因为这很耗时。

此示例适用于Infragistics,但该原则同样适用于其他优秀的库,例如DevExpress。

的Xaml

<ig:TemplateColumn Key="ColumnKey">
    <ig:TemplateColumn.HeaderTemplate>
        <DataTemplate>
            <TextBlock Text="Header"></TextBlock>
        </DataTemplate>
    </ig:TemplateColumn.HeaderTemplate>
    <ig:TemplateColumn.ItemTemplate>
        <DataTemplate>
            <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <StackPanel.ToolTip>
                    <TextBlock Text="{Binding ToolTip}"/>
                </StackPanel.ToolTip>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseEnter" >
                        <i:InvokeCommandAction Command="{Binding ToolTipHoverRefreshCommand}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </StackPanel>
        </DataTemplate>
    </ig:TemplateColumn.ItemTemplate>
</ig:TemplateColumn>

视图模型

public ICommand ToolTipHoverRefreshCommand => new DelegateCommand(() =>
{
    this.OnPropertyChanged(this.ToolTip);
});  

public string ToolTip
{
    get
    {
        return DateTime.Now.ToString();
    }
    set
    {
        this.OnPropertyChanged(nameof(this.ToolTip));
    }
}

答案 4 :(得分:0)

我遇到了同样的问题,即它没有更新。我发现解决方案是将控件添加到ToolTip模板中:

<DataTemplate DataType={x:Type Staff}>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text={Binding FirstName}/>
        <TextBlock Text=" ">
        <TextBlock Text={Binding FamilyName}/>
        <StackPanel.ToolTip>
            <Tooltip>
                <ToolTip.Template>
                    <ControlTemlate>
                        <TextBlock Text={Binding SecondsAlive}/>
                    </ControlTemplate>
                </ToolTip.Template>
            </Tooltip> 
        </StackPanel.ToolTip>
     </StackPanel>
</DataTemplate>

我不太了解为什么需要这样做,或者为什么这样做会使行为有所不同,但解决了问题。