wake-up-neo.net

Erzwingen, dass ein WPF-Tooltip auf dem Bildschirm angezeigt wird

Ich habe einen Tooltip für ein Label, und ich möchte, dass es geöffnet bleibt, bis der Benutzer die Maus auf ein anderes Steuerelement bewegt.

Ich habe folgende Eigenschaften des Tooltips ausprobiert:

StaysOpen="True"

und

TooltipService.ShowDuration = "60000"

In beiden Fällen wird der Tooltip jedoch nur für genau 5 Sekunden angezeigt.

Warum werden diese Werte ignoriert?

101
TimothyP

Fügen Sie diesen Code einfach in den Initialisierungsabschnitt ein. 

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

TooltipService.ShowDuration funktioniert, aber Sie müssen es für das Objekt mit dem Tooltip wie folgt festlegen:

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

Ich würde sagen, dass dieses Design gewählt wurde, weil es die gleichen QuickInfos mit unterschiedlichen Timeouts für verschiedene Steuerelemente zulässt.

163
Martin Konicek

Das hat mich heute Nacht auch verrückt gemacht. Ich habe eine ToolTip-Unterklasse erstellt, um das Problem zu lösen. Für mich unter .NET 4.0 ist die ToolTip.StaysOpen-Eigenschaft nicht "wirklich" geöffnet. 

Verwenden Sie in der folgenden Klasse die neue Eigenschaft ToolTipEx.IsReallyOpen anstelle der Eigenschaft ToolTip.IsOpen. Sie erhalten die gewünschte Kontrolle. Über den Aufruf Debug.Print() können Sie im Ausgabefenster des Debuggers beobachten, wie oft this.IsOpen = false aufgerufen wird! Soviel zu StaysOpen, oder sollte ich "StaysOpen" sagen? Genießen.

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);
        }
    }
}

Kleine Kritik: Warum hat Microsoft DependencyProperty-Eigenschaften (Getter/Setter) nicht virtuell gemacht, damit wir Änderungen in Unterklassen akzeptieren/ablehnen/anpassen können? Oder machen Sie einen virtual OnXYZPropertyChanged für jede und jede DependencyProperty? Pfui.

---Bearbeiten---

Meine obige Lösung sieht im XAML-Editor seltsam aus - der Tooltip wird immer angezeigt und blockiert Text in Visual Studio!

Hier ist ein besserer Weg, um dieses Problem zu lösen:

Einige 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>

Etwas 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);
    }
}

Fazit: Die Klassen ToolTip und ContextMenu unterscheiden sich etwas. Beide verfügen über "Service" -Klassen wie ToolTipService und ContextMenuService, die bestimmte Eigenschaften verwalten, und beide verwenden Popup als "geheimes" übergeordnetes Steuerelement während der Anzeige. Schließlich habe ich festgestellt, dass ALL die XAML-ToolTip-Beispiele im Web die Klasse ToolTip nicht direkt verwenden. Stattdessen wird eine StackPanel mit TextBlocks eingebettet. Dinge, die Sie dazu bringen, zu sagen: "hmmm ..."

14
kevinarpe

Sie möchten wahrscheinlich Popup anstelle von Tooltip verwenden, da Tooltip davon ausgeht, dass Sie es auf vordefinierte UI-Standards verwenden.

Ich bin nicht sicher, warum StaysOpen nicht funktioniert, aber ShowDuration funktioniert wie in MSDN dokumentiert. Dies ist die Zeit, in der der Tooltip angezeigt wird, WENN er angezeigt wird. Stellen Sie den Wert auf einen kleinen Wert (z. B. 500 ms), um den Unterschied zu sehen.

Der Trick in Ihrem Fall ist das Beibehalten des Status "last hovered control", aber sobald Sie wissen, dass es ziemlich trivial sein sollte, das Platzierungsziel und den Inhalt dynamisch zu ändern (entweder manuell oder per Bindung), wenn Sie ein Popup verwenden, oder das letzte sichtbare Popup ausblenden, wenn Sie mehrere verwenden.

Es gibt einige Kniffe mit Popups bis hin zur Größenänderung und Verschiebung von Fenstern (Popups bewegen sich nicht mit den Containern). Daher möchten Sie vielleicht auch daran denken, während Sie das Verhalten optimieren. Siehe diesen Link für weitere Details.

HTH.

8
micahtan

Wenn Sie angeben möchten, dass nur bestimmte Elemente in Ihrer Window eine ToolTip Dauer haben, können Sie eine Style in Ihrem Window.Resources für diese Elemente definieren. Hier ist eine Style für Button, die eine solche ToolTip hat:

<Window
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;Assembly=mscorlib"
    ...>
    ...
    <Window.Resources>
        <Style x:Key="ButtonToolTipIndefinate" TargetType="{x:Type Button}">
            <Setter Property="ToolTipService.ShowDuration"
                    Value="{x:Static Member=sys:Int32.MaxValue}"/>
        </Style>
        ...
    </Window.Resources>
    ...
    <Button Style="{DynamicResource ButtonToolTipIndefinate}"
            ToolTip="This should stay open"/>
    <Button ToolTip="This Should disappear after the default time.">
    ...

Sie können auch Style.Resources zur Style hinzufügen, um das Erscheinungsbild der ToolTip zu ändern, die angezeigt wird. Beispiel:

<Style x:Key="ButtonToolTipTransparentIndefinate" TargetType="{x:Type Button}">
    <Style.Resources>
        <Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="HasDropShadow" Value="False"/>
        </Style>
    </Style.Resources>
    <Setter Property="ToolTipService.ShowDuration"
            Value="{x:Static Member=sys:Int32.MaxValue}"/>
</Style>

Hinweis: Wenn ich dies tat, habe ich auch BasedOn in der Style verwendet, damit alles andere, was für die Version meines benutzerdefinierten Steuerelements mit einer normalen ToolTip definiert ist, angewendet wird.

7
Jonathan Allan

Ich habe erst neulich mit dem WPF-Tooltip gerungen. Es scheint nicht möglich zu sein, das Erscheinen und Verschwinden von selbst zu verhindern, also habe ich mich letztendlich darauf konzentriert, das Ereignis Opened zu behandeln. Zum Beispiel wollte ich es nicht öffnen, es sei denn, es hatte einen Inhalt. Daher behandelte ich das Ereignis Opened und tat Folgendes:

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

Es ist ein Hack, aber es hat funktioniert.

Vermutlich könnten Sie das Closed-Ereignis auf ähnliche Weise handhaben und es wieder öffnen, damit es sichtbar bleibt.

5

Nur der Vollständigkeit halber: Im Code sieht es so aus:

ToolTipService.SetShowDuration(element, 60000);
2
Ulrich Beckert

Ich habe mein Problem mit demselben Code behoben.

ToolTipService.ShowDurationProperty.OverrideMetadata ( Typeof (DependencyObject), neues FrameworkPropertyMetadata (Int32.MaxValue));

0
Aravind S

Wenn Sie jemals ein anderes Steuerelement in die QuickInfo einfügen möchten, ist es nicht fokussierbar, da eine QuickInfo selbst den Fokus erhält. Wie Micahtan gesagt hat, ist dein bester Schuss ein Popup.

0
Carlo