109 votes

Forcer une info-bulle WPF à rester à l'écran

J'ai une info-bulle pour une étiquette et je veux qu'elle reste ouverte jusqu'à ce que l'utilisateur déplace la souris sur un contrôle différent.

J'ai essayé les propriétés suivantes sur l'info-bulle:

 StaysOpen="True"
 

et

 TooltipService.ShowDuration = "60000"
 

Mais dans les deux cas, l'info-bulle ne s'affiche que pendant exactement 5 secondes.

Pourquoi ces valeurs sont-elles ignorées?

169voto

Martin Konicek Points 7999

TooltipService.ShowDuration fonctionne, mais vous devez le définir sur l'objet ayant l'info-bulle, comme ceci:

 <Label ToolTipService.ShowDuration="12000" Name="lblShowTooltip" Content="Shows tooltip">
    <Label.ToolTip>
        <ToolTip>
            <TextBlock>Hello world!</TextBlock>
        </ToolTip>
    </Label.ToolTip>
</Label>
 

Je dirais que cette conception a été choisie car elle permet la même infobulle avec différents délais d'expiration sur différentes commandes.

100voto

John Whiter Points 176

Il suffit de mettre ce code dans la section d'initialisation.

 ToolTipService.ShowDurationProperty.OverrideMetadata(
    typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
 

15voto

kevinarpe Points 2902

Ce fut aussi, me rend fou ce soir. J'ai créé un ToolTip sous-classe pour gérer la question. Pour moi, sur .NET 4.0, l' ToolTip.StaysOpen de la propriété n'est pas "vraiment" reste ouverte.

Dans la classe ci-dessous, utiliser la nouvelle propriété ToolTipEx.IsReallyOpen, au lieu de la propriété ToolTip.IsOpen. Vous obtiendrez le contrôle que vous souhaitez. Via l' Debug.Print() appel, vous pouvez regarder dans la fenêtre Sortie du débogueur juste combien de fois this.IsOpen = false est appelé! Autant pour l' StaysOpen, ou devrais-je dire "StaysOpen"? Profitez de.

public class ToolTipEx : ToolTip
{
    static ToolTipEx()
    {
        IsReallyOpenProperty =
            DependencyProperty.Register(
                "IsReallyOpen",
                typeof(bool),
                typeof(ToolTipEx),
                new FrameworkPropertyMetadata(
                    defaultValue: false,
                    flags: FrameworkPropertyMetadataOptions.None,
                    propertyChangedCallback: StaticOnIsReallyOpenedChanged));
    }

    public static readonly DependencyProperty IsReallyOpenProperty;

    protected static void StaticOnIsReallyOpenedChanged(
        DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        ToolTipEx self = (ToolTipEx)o;
        self.OnIsReallyOpenedChanged((bool)e.OldValue, (bool)e.NewValue);
    }

    protected void OnIsReallyOpenedChanged(bool oldValue, bool newValue)
    {
        this.IsOpen = newValue;
    }

    public bool IsReallyOpen
    {
        get
        {
            bool b = (bool)this.GetValue(IsReallyOpenProperty);
            return b;
        }
        set { this.SetValue(IsReallyOpenProperty, value); }
    }

    protected override void OnClosed(RoutedEventArgs e)
    {
        System.Diagnostics.Debug.Print(String.Format(
            "OnClosed: IsReallyOpen: {0}, StaysOpen: {1}", this.IsReallyOpen, this.StaysOpen));
        if (this.IsReallyOpen && this.StaysOpen)
        {
            e.Handled = true;
            // We cannot set this.IsOpen directly here.  Instead, send an event asynchronously.
            // DispatcherPriority.Send is the highest priority possible.
            Dispatcher.CurrentDispatcher.BeginInvoke(
                (Action)(() => this.IsOpen = true),
                DispatcherPriority.Send);
        }
        else
        {
            base.OnClosed(e);
        }
    }
}

Petit coup de gueule: Pourquoi ne pas Microsoft font DependencyProperty propriétés (getters/setters) virtuel de sorte que nous pouvons accepter/rejeter/ajuster les changements dans les sous-classes? Ou faire un virtual OnXYZPropertyChanged pour chaque DependencyProperty? Ugh.

---Edit---

Ma solution ci-dessus semble bizarre dans l'éditeur XAML -- l'info-bulle est toujours présente, le blocage de certains de texte dans Visual Studio!

Ici, c'est une meilleure façon de résoudre ce problème:

Certains XAML:

<!-- Need to add this at top of your XAML file:
     xmlns:System="clr-namespace:System;assembly=mscorlib"
-->
<ToolTip StaysOpen="True" Placement="Bottom" HorizontalOffset="10"
        ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="0"
        ToolTipService.ShowDuration="{x:Static Member=System:Int32.MaxValue}"
>This is my tooltip text.</ToolTip>

Un peu de code:

// Alternatively, you can attach an event listener to FrameworkElement.Loaded
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    // Be gentle here: If someone creates a (future) subclass or changes your control template,
    // you might not have tooltip anymore.
    ToolTip toolTip = this.ToolTip as ToolTip;
    if (null != toolTip)
    {
        // If I don't set this explicitly, placement is strange.
        toolTip.PlacementTarget = this;
        toolTip.Closed += new RoutedEventHandler(OnToolTipClosed);
    }
}

protected void OnToolTipClosed(object sender, RoutedEventArgs e)
{
    // You may want to add additional focus-related tests here.
    if (this.IsKeyboardFocusWithin)
    {
        // We cannot set this.IsOpen directly here.  Instead, send an event asynchronously.
        // DispatcherPriority.Send is the highest priority possible.
        Dispatcher.CurrentDispatcher.BeginInvoke(
            (Action)delegate
                {
                    // Again: Be gentle when using this.ToolTip.
                    ToolTip toolTip = this.ToolTip as ToolTip;
                    if (null != toolTip)
                    {
                        toolTip.IsOpen = true;
                    }
                },
            DispatcherPriority.Send);
    }
}

Conclusion: quelque Chose est différent sur les classes ToolTip et ContextMenu. Les deux ont "service" des classes, comme ToolTipService et ContextMenuService, qui gèrent certaines propriétés, et les deux utilisent des Popup comme un "secret" parent de contrôle lors de l'affichage. Enfin, j'ai remarqué que TOUS les XAML info-bulle des exemples sur le Web ne pas utiliser de classe ToolTip directement. Au lieu de cela, ils intégrer un StackPanel avec TextBlocks. Des choses qui vous font dire: "hmmm..."

8voto

micahtan Points 6457

Vous voudrez probablement utiliser Popup au lieu de l'info-bulle, depuis info-bulle suppose que vous l'utilisez dans le pré-défini de l'INTERFACE utilisateur-normes.

Je ne sais pas pourquoi StaysOpen ne fonctionne pas, mais ShowDuration fonctionne comme documenté dans la MSDN, c'est la quantité de temps que l'info-bulle s'affiche LORS de l'affichage. Ensemble pour une petite quantité (par exemple, 500 msec) pour voir la différence.

Le truc, dans votre cas, est le maintien de la "dernière a plané" contrôle de l'état, mais une fois que vous avez qu'il devrait être assez trivial pour changer l'emplacement de la cible et le contenu de manière dynamique (soit manuellement, soit via la liaison) si vous utilisez un pop-up, ou en cachant la dernière visible Popup si vous utilisez plusieurs.

Il y a quelques problèmes avec les fenêtres pop-up d'autant que la Fenêtre de redimensionnement et déplacement (Popups ne pas déplacer w/conteneurs), de sorte que vous pouvez également avoir à l'esprit pendant que vous êtes à peaufiner le comportement. Voir ce lien pour plus de détails.

HTH.

5voto

Daniel Earwicker Points 63298

J'ai été aux prises avec WPF info-bulle que l'autre jour. Il ne semble pas être possible pour l'empêcher d'apparaître et disparaître par lui-même, de sorte que dans la fin, j'ai eu recours à la manipulation de la Opened événement. Par exemple, j'ai voulu arrêter l'ouverture, sauf si elle avait un peu de contenu, de sorte que j'ai manipulé la Opened événement, puis fait ceci:

tooltip.IsOpen = (tooltip.Content != null);

C'est un hack, mais cela a fonctionné.

Je suppose que vous pourrait également gérer l' Closed événement et dites-lui de s'ouvrir de nouveau, gardant ainsi visible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: