एक WPF टूलटिप को स्क्रीन पर रहने के लिए मजबूर करना


119

मेरे पास एक लेबल के लिए एक टूलटिप है और मैं चाहता हूं कि यह तब तक खुला रहे जब तक कि उपयोगकर्ता माउस को एक अलग नियंत्रण में न ले जाए।

मैंने टूलटिप पर निम्नलिखित गुणों की कोशिश की है:

StaysOpen="True"

तथा

ToolTipService.ShowDuration = "60000"

लेकिन दोनों ही मामलों में टूलटिप केवल 5 सेकंड के लिए प्रदर्शित होता है।

इन मूल्यों की अनदेखी क्यों की जा रही है?


संपत्ति के लिए कहीं अधिक मूल्य लागू किया गया ShowDurationहै, सोचें कि यह कुछ ऐसा है 30,000। इससे अधिक कुछ भी और यह डिफ़ॉल्ट रूप से वापस आ जाएगा 5000
डेनिस

2
@ डेनिस: मैंने WPF 3.5 के साथ यह परीक्षण किया और ToolTipService.ShowDuration="60000"काम किया। यह वापस करने के लिए डिफ़ॉल्ट नहीं था 5000
एम। डुडले

@emddudley: क्या टूलटिप वास्तव में 60000ms के लिए खुला रहता है? आप ToolTipService.ShowDurationसंपत्ति को किसी भी मूल्य> = 0 (Int32.MaxValue) पर सेट कर सकते हैं, हालांकि टूलटिप उस लंबाई के लिए खुला नहीं रहेगा।
डेनिस

2
@ डेनिस: हाँ, यह बिल्कुल 60 सेकंड के लिए खुला रहा। यह विंडोज 7.
एम। डडले

@emddudley: यह अंतर हो सकता है। यह ज्ञान था जब मैं विंडोज एक्सपी के खिलाफ विकसित हो रहा था।
डेनिस

जवाबों:


113

बस इस कोड को इनिशियलाइज़ेशन सेक्शन में रखें।

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

यह एकमात्र समाधान था जिसने मेरे लिए काम किया। आप नियुक्ति कोड को शीर्ष पर सेट करने के लिए इस कोड को कैसे अनुकूलित कर सकते हैं? new FrameworkPropertyMetadata("Top")काम नहीं करता है।
InvalidBrainException

6
मैंने इसे (लगभग 6 वर्षों के बाद, खेद के रूप में) सही उत्तर के रूप में चिह्नित किया है क्योंकि यह वास्तव में विंडोज के सभी समर्थित संस्करणों पर काम करता है और इसे 49 दिनों तक खुला रखता है, जो लंबे समय तक पर्याप्त होना चाहिए: पी
टिमोथी

1
मैंने इसे अपने Window_Loaded घटना में भी रखा है और यह बहुत अच्छा काम करता है। केवल एक चीज जो आपको करनी है, वह यह है कि आप किसी भी "टूलटिप सर्विस सर्विस" से छुटकारा पाएं जो आपने अपने एक्सएएमएल में सेट किया है, एक्सएएमएल में आपके द्वारा निर्धारित अवधि उस व्यवहार को ओवरराइड कर देगी जिसे यह कोड प्राप्त करने की कोशिश कर रहा है। समाधान प्रदान करने के लिए जॉन व्हिटर का धन्यवाद।
2

1
एफडब्ल्यूआईडब्ल्यू, मैं इसे ठीक-ठीक पसंद करता हूं क्योंकि यह वैश्विक है - मैं चाहता हूं कि मेरे ऐप के सभी टूलटिप्स आगे की धूमधाम के बिना लंबे समय तक बने रहें। ऐसा करने से आप संदर्भ-विशिष्ट स्थानों में छोटे मूल्य को चुन सकते हैं, साथ ही साथ अन्य उत्तर में भी। (लेकिन हमेशा की तरह, यह केवल तभी मान्य है जब आप अनुप्रयोग हैं - यदि आप एक नियंत्रण पुस्तकालय या कुछ और लिख रहे हैं, तो आपको केवल संदर्भ-विशिष्ट समाधानों का उपयोग करना चाहिए ; वैश्विक स्थिति आपके साथ खेलने के लिए नहीं है।)
मिरल

1
यह खतरनाक हो सकता है! Wpf आंतरिक रूप से TimeSpan का उपयोग करता है। FromMilliseconds () टाइमर अंतराल सेट करते समय जो दोहरी गणना करता है। इसका मतलब है कि जब इंटरवल प्रॉपर्टी का उपयोग करके टाइमर पर मूल्य लागू किया जाता है तो आप ArgumentOutOfRangeException प्राप्त कर सकते हैं।
जनवरी

190

TooltipService.ShowDuration काम करता है, लेकिन आपको टूलटिप की वस्तु पर इसे इस तरह सेट करना होगा:

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

मैं कहूंगा कि इस डिज़ाइन को इसलिए चुना गया क्योंकि यह एक ही टूलटिप को अलग-अलग समय पर अलग-अलग नियंत्रणों के साथ अनुमति देता है।


4
यह आपको ToolTipस्पष्ट के बिना सीधे की सामग्री को निर्दिष्ट करने की भी अनुमति देता है <ToolTip>, जो बाध्यकारी को सरल बना सकता है।
svick

15
यह चुना हुआ उत्तर होना चाहिए क्योंकि यह संदर्भ विशिष्ट है और वैश्विक नहीं है।
व्लाद

8
अवधि मिलीसेकंड में है। डिफ़ॉल्ट 5000 है। ऊपर दिया गया कोड 12 सेकंड निर्दिष्ट करता है।
कंटैंगो

1
यदि आप एक ही टूलटिप उदाहरण का उपयोग कई नियंत्रणों के साथ करते हैं जो आप जल्दी या बाद में "एक अलग माता-पिता के पहले से ही दृश्य बच्चे" को प्राप्त करेंगे।
बसंत 4६

1
इसका सही कारण होना चाहिए इसका मुख्य कारण यह है कि यह वास्तविक उच्च स्तरीय प्रोग्रामिंग, XAML कोड में सही, और नोटिस करने में आसान है। अन्य समाधान थोड़े हैसी और क्रिया के अलावा बिंदु के अलावा यह वैश्विक है। मैंने उन अधिकांश लोगों को धोखा दिया जो उस का उपयोग करते थे, यह भूल गए कि उन्होंने एक सप्ताह में यह कैसे किया।
j riv

15

यह भी मुझे आज रात पागल कर रहा था। मैंने ToolTipइस मुद्दे को संभालने के लिए एक उपवर्ग बनाया । मेरे लिए, .NET 4.0 पर, ToolTip.StaysOpenसंपत्ति "वास्तव में" खुली नहीं रहती है।

नीचे की कक्षा में, संपत्ति ToolTipEx.IsReallyOpenके बजाय, नई संपत्ति का उपयोग करें ToolTip.IsOpen। आपको मनचाहा नियंत्रण मिलेगा। Debug.Print()कॉल के माध्यम से , आप डिबगर आउटपुट विंडो में देख सकते हैं कि कितनी बार this.IsOpen = falseकॉल किया जाता है! के लिए इतना StaysOpen, या मुझे कहना चाहिए "StaysOpen"? का आनंद लें।

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

छोटा शेख़ी: माइक्रोसॉफ्ट ने DependencyPropertyगुण (गेटर्स / सेटर) को आभासी क्यों नहीं बनाया ताकि हम उपवर्गों में बदलावों को स्वीकार / अस्वीकार / समायोजित कर सकें? या हर एक के virtual OnXYZPropertyChangedलिए एक बनाने के लिए DependencyProperty? ओह।

--- संपादित करें ---

ऊपर का मेरा समाधान XAML संपादक में अजीब लग रहा है - टूलटिप हमेशा दिखा रहा है, विजुअल स्टूडियो में कुछ पाठ को अवरुद्ध कर रहा है!

यहाँ इस समस्या को हल करने का एक बेहतर तरीका है:

कुछ 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>

कुछ कोड:

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

निष्कर्ष: कुछ कक्षाओं के बारे में अलग है ToolTipऔर ContextMenu। दोनों में "सेवा" वर्ग हैं, जैसे ToolTipServiceऔर ContextMenuService, जो कुछ गुणों का प्रबंधन करते हैं, और दोनों Popupप्रदर्शन के दौरान "गुप्त" मूल नियंत्रण के रूप में उपयोग करते हैं। अंत में, मैंने देखा कि वेब पर सभी XAML टूलटिप उदाहरण ToolTipसीधे वर्ग का उपयोग नहीं करते हैं। इसके बजाय, वे एस के StackPanelसाथ एम्बेड करते हैं TextBlock। चीजें जो आपको कहती हैं: "हम्म्म ..."


1
आपको अपने उत्तर पर और अधिक वोट प्राप्त करने चाहिए। मुझ से +1।
हन्नीस

टूलटाइप सेवा को मूल तत्व पर रखा जाना चाहिए, ऊपर मार्टिन कोनिसक का उत्तर देखें।
जेसन मार्ताज्या

8

आप शायद टूलटिप के बजाय पॉपअप का उपयोग करना चाहते हैं, क्योंकि टूलटिप मानता है कि आप इसे पूर्व-निर्धारित यूआई-मानक तरीके से उपयोग कर रहे हैं।

मुझे यकीन नहीं है कि StaysOpen काम क्यों नहीं करता है, लेकिन ShowDuration MSDN में प्रलेखित के रूप में काम करता है - यह टूलटिप के प्रदर्शित होने के समय की मात्रा है। अंतर देखने के लिए इसे थोड़ी मात्रा (जैसे 500 मिसे) पर सेट करें।

आपके मामले में चाल "अंतिम होवर किए गए नियंत्रण" स्थिति को बनाए रख रही है, लेकिन एक बार आपके पास यह है कि प्लेसमेंट लक्ष्य और सामग्री को गतिशील रूप से बदलने के लिए काफी तुच्छ होना चाहिए (या तो मैन्युअल रूप से, या बाध्यकारी के माध्यम से) यदि आप एक पॉपअप का उपयोग कर रहे हैं, या यदि आप एकाधिक का उपयोग कर रहे हैं, तो अंतिम दृश्य पॉपअप छिपा रहे हैं।

पॉपअप के साथ कुछ गोचर्स हैं जहाँ तक विंडो का आकार बदलना और बढ़ना (पॉपअप w / कंटेनरों को नहीं हिलाते हैं), इसलिए आप यह भी सोच सकते हैं कि व्यवहार को ट्विक करते समय आपके दिमाग में भी यह हो। देखें इस लिंक अधिक जानकारी के लिए।

HTH।


3
यह भी सावधान रहें कि पॉपअप हमेशा सभी डेस्कटॉप ऑब्जेक्ट्स में सबसे ऊपर होता है - भले ही आप किसी अन्य प्रोग्राम पर स्विच करें, पॉपअप अन्य प्रोग्राम का दृश्य और अस्पष्ट हिस्सा होगा।
जेफ बी

यही कारण है कि मुझे पॉपअप का उपयोग करना पसंद नहीं है .... क्योंकि वे कार्यक्रम के साथ सिकुड़ते नहीं हैं और वे अन्य सभी कार्यक्रमों में शीर्ष पर रहते हैं। इसके अलावा, मुख्य अनुप्रयोग का आकार बदलना / बढ़ना इसके साथ पॉपअप को डिफ़ॉल्ट रूप से स्थानांतरित नहीं करता है।
राहेल

FWIW, यह यूआई सम्मेलन वैसे भी बकवास है । कुछ चीजें टूलटिप की तुलना में अधिक कष्टप्रद होती हैं जो मुझे पढ़ते समय गायब हो जाती हैं।
रोमन स्टार्कोव

7

यदि आप यह निर्दिष्ट करना चाहते हैं कि आपके तत्वों में केवल कुछ तत्व Windowप्रभावी रूप से अनिश्चित काल के लिए हैं तो ToolTipआप उन तत्वों के लिए Styleअपने में परिभाषित कर सकते हैं Window.Resources। यहाँ एक के Styleलिए है Buttonकि इस तरह है ToolTip:

<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.">
    ...

एक भी जोड़ सकते हैं Style.Resourcesकरने के लिए Styleकी उपस्थिति को बदलने के लिए ToolTipउदाहरण के लिए, यह पता चलता है:

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

नोट: जब मैं इस मैं भी इस्तेमाल किया किया था BasedOnमें Styleसब कुछ किसी और एक सामान्य के साथ अपने कस्टम नियंत्रण के संस्करण के लिए परिभाषित किया गया तो ToolTipलागू किया जाएगा।


5

मैं दूसरे दिन केवल WPF टूलटिप के साथ कुश्ती कर रहा था। ऐसा प्रतीत नहीं होता कि इसे प्रकट होने से रोकना और स्वयं से गायब होना संभव है, इसलिए अंत में मैंने इस Openedघटना को संभालने का सहारा लिया । उदाहरण के लिए, मैं इसे खोलने से रोकना चाहता था जब तक कि इसमें कुछ सामग्री न हो, इसलिए मैंने इस Openedघटना को संभाला और फिर ऐसा किया:

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

यह एक हैक है, लेकिन यह काम किया।

संभवत: आप इसी तरह से Closedघटना को संभाल सकते हैं और इसे फिर से खोलने के लिए कह सकते हैं, इस प्रकार इसे दृश्यमान रख सकते हैं।


टूलटिप में एक संपत्ति है जिसे हस्सेंटेंट कहा जाता है जिसे आप इसके बजाय इस्तेमाल कर सकते हैं
बेनपियरस


0

यदि आप कभी भी अपने टूलटिप में कोई अन्य नियंत्रण रखना चाहते हैं, तो यह ध्यान देने योग्य नहीं होगा क्योंकि टूलटिप स्वयं फोकस प्राप्त कर सकता है। तो लाइक माइकटन ने कहा, आपका सबसे अच्छा शॉट एक पॉपअप है।


0

एक ही कोड के साथ तय की गई मेरी समस्या।

ToolTipService.ShowDurationProperty.OverrideMetadata (typeof (DependencyObject), नया FrameworkPropertyMetadata (Int32.MaxValue));


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

यह मेरे लिए काम कर रहा है। इस लाइन को अपने क्लास कंस्ट्रक्टर में कॉपी करें।


3
यह दूसरे सबसे ऊपर के साथ स्वीकार किए गए उत्तर की कॉपी और पेस्ट है
कोडिंगयूरलाइफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.