WPF 도구 설명이 화면에 유지되도록 강제


119

레이블에 대한 도구 설명이 있고 사용자가 마우스를 다른 컨트롤로 이동할 때까지 열려 있기를 원합니다.

툴팁에서 다음 속성을 시도했습니다.

StaysOpen="True"

ToolTipService.ShowDuration = "60000"

그러나 두 경우 모두 툴팁은 정확히 5 초 동안 만 표시됩니다.

이 값이 무시되는 이유는 무엇입니까?


최대 값이 적용이 에 대한 ShowDuration특성, 그것은 같은 것입니다 생각합니다 30,000. 그보다 큰 값은 기본적으로 5000.
Dennis

2
@Dennis : 나는 이것을 WPF 3.5로 테스트하고 ToolTipService.ShowDuration="60000"작동했습니다. 기본값은 5000.
M. Dudley 2011

@emddudley : 툴팁이 실제로 60000ms 동안 열려 있습니까? 당신은 설정할 수 있습니다 ToolTipService.ShowDuration에 속성을 어떤 값 (Int32.MaxValue에)> = 0 그러나 툴팁이 그 기간 동안 영업을하지 않습니다.
Dennis

2
@Dennis : 예, 정확히 60 초 동안 열려있었습니다. 이것은 Windows 7에 있습니다.
M. Dudley

@emddudley : 그게 차이 일 수 있습니다. 이것은 제가 Windows XP에 대해 개발할 때 얻은 지식이었습니다.
Dennis

답변:


113

이 코드를 초기화 섹션에 넣으십시오.

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

이것은 나를 위해 일한 유일한 솔루션이었습니다. 이 코드를 적용하여 Placement 속성을 Top으로 설정하려면 어떻게해야합니까? new FrameworkPropertyMetadata("Top")작동하지 않습니다.
InvalidBrainException

6
실제로 지원되는 모든 Windows 버전에서 작동하고 49 일 동안 열어
두기

1
나는 또한 이것을 내 Window_Loaded 이벤트에 넣었고 훌륭하게 작동합니다. 해야 할 일은 XAML에서 설정 한 "ToolTipService.ShowDuration"을 제거하는 것뿐입니다. XAML에서 설정 한 기간은이 코드가 달성하려는 동작을 재정의합니다. 솔루션을 제공 한 John Whiter에게 감사드립니다.
nicko

1
FWIW, 나는 이것이 글로벌이기 때문에 정확하게 이것을 선호합니다. 내 앱의 모든 툴팁이 더 이상 팡파르없이 더 오래 지속되기를 바랍니다. 이렇게하면 다른 답변과 마찬가지로 상황에 맞는 장소에서도 더 작은 값을 선택적으로 적용 할 수 있습니다. (그러나 항상 그렇듯이 이것은 당신이 애플리케이션 인 경우에만 유효합니다. 컨트롤 라이브러리 나 다른 것을 작성한다면 상황 별 솔루션 만 사용해야 합니다 . 글로벌 상태는 당신의 것이 아닙니다.)
Miral

1
이것은 위험 할 수 있습니다! Wpf는 이중 계산을 수행하는 타이머 간격을 설정할 때 내부적으로 TimeSpan.FromMilliseconds ()를 사용합니다. 즉, Interval 속성을 사용하여 값이 타이머에 적용되면 ArgumentOutOfRangeException을 얻을 수 있습니다.
1

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
이것은 글로벌이 아닌 문맥에 따라 선택되어야합니다.
Vlad 2015

8
기간은 밀리 초 단위입니다. 기본값은 5000입니다. 위 코드는 12 초를 지정합니다.
Contango 2015-06-10

1
여러 컨트롤과 함께 동일한 도구 설명 인스턴스를 사용하는 경우 조만간 "다른 부모의 이미 시각적 자식"예외가 발생합니다.
springy76

1
이것이 정답이되어야하는 주된 이유는 XAML 코드에 대한 실제 고수준 프로그래밍의 정신에 있고 쉽게 알아 차릴 수 있기 때문입니다. 다른 해결책은 글로벌이라는 점 외에도 다소 엉망이고 장황합니다. 나는 그것을 사용하는 대부분의 사람들이 일주일 동안 그것을 어떻게했는지 잊어 버렸습니다.
j riv 13

15

이것은 또한 오늘 밤 나를 미치게 만들었다. ToolTip문제를 처리하기 위해 하위 클래스를 만들었습니다 . 나를 위해 .NET 4.0에서ToolTip.StaysOpen 속성은 "정말"이 열려 있지 않습니다.

아래 클래스 ToolTipEx.IsReallyOpen에서 property 대신 new property를 사용하십시오 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);
        }
    }
}

작은 폭언 : Microsoft는 왜 DependencyProperty속성 (getters / setters)을 가상으로 만들어서 하위 클래스의 변경 사항을 수락 / 거부 / 조정할 수 없었 습니까? 아니면을 virtual OnXYZPropertyChanged각각의 모든에 대해DependencyProperty ? 으.

---편집하다---

위의 솔루션은 XAML 편집기에서 이상하게 보입니다. 도구 설명이 항상 표시되어 Visual Studio에서 일부 텍스트를 차단합니다!

이 문제를 해결하는 더 좋은 방법은 다음과 같습니다.

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

결론 : 클래스 ToolTipContextMenu. 모두 "서비스"와 같은 클래스가 ToolTipServiceContextMenuService, 특정 속성을 관리하고, 모두 사용하는 Popup디스플레이 중 "비밀"부모 컨트롤로합니다. 마지막으로 웹의 모든 XAML 도구 설명 예제는 클래스를 ToolTip직접 사용하지 않습니다 . 대신 StackPanelwith TextBlocks 를 포함합니다 . 당신이 말하는 것 : "흠 ..."


1
철저한 답변에 대해 더 많은 표를 얻어야합니다. 나에게서 +1.
Hannish 2013.04.05

ToolTipService는 상위 요소에 배치되어야합니다. 위의 Martin Konicek의 답변을 참조하십시오.
Jeson Martajaya 19

8

Tooltip은 미리 정의 된 UI 표준 방식으로 사용하고 있다고 가정하므로 Tooltip 대신 Popup을 사용하고 싶을 것입니다.

StaysOpen이 작동하지 않는 이유는 모르겠지만 ShowDuration은 MSDN에 문서화 된대로 작동합니다. 도구 설명이 표시 될 때 표시되는 시간입니다. 차이를 확인하려면 소량 (예 : 500msec)으로 설정하십시오.

귀하의 경우 트릭은 "마지막 호 버드 컨트롤"상태를 유지하는 것입니다.하지만 일단 Popup을 사용하는 경우 배치 대상과 콘텐츠를 동적으로 (수동으로 또는 바인딩을 통해) 변경하는 것은 매우 간단해야합니다. 여러 개를 사용하는 경우 마지막으로 보이는 팝업을 숨 깁니다.

창 크기 조정 및 이동 (팝업은 컨테이너와 함께 이동하지 않음)과 관련하여 팝업과 관련된 몇 가지 문제가 있으므로 동작을 조정하는 동안이를 염두에 둘 수도 있습니다. 이 링크 보기 를 참조하십시오.

HTH.


3
또한 팝업은 항상 모든 데스크톱 개체의 맨 위에 있습니다. 다른 프로그램으로 전환하더라도 팝업이 다른 프로그램의 일부를 가리고 표시됩니다.
Jeff B

그것이 바로 내가 팝업을 사용하는 것을 좋아하지 않는 이유입니다 .... 그들은 프로그램과 함께 축소되지 않고 다른 모든 프로그램 위에 머물러 있기 때문입니다. 또한 기본 응용 프로그램의 크기를 조정 / 이동해도 기본적으로 팝업이 이동하지 않습니다.
Rachel

FWIW,이 UI 규칙 은 어쨌든 쓰레기입니다 . 읽는 동안 사라지는 툴팁보다 더 짜증나는 것은 없습니다.
Roman Starkov 2014

7

의 특정 요소 만 Window유효 ToolTip기간을 무기한 으로 지정하려면 해당 요소에 대해 Stylein을 정의 할 수 있습니다 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>

참고 :이 작업을 수행 할 때 BasedOnStyle다른 정상적인 내 사용자 지정 컨트롤의 버전에 대해 정의 그래서 모든 것을 ToolTip적용 할 수있다.


5

전날 WPF 툴팁과 씨름하고있었습니다. 저절로 나타나고 사라지는 것을 막을 수없는 것 같아서 결국 Opened이벤트 를 처리했습니다 . 예를 들어, 콘텐츠가없는 경우 열리지 않도록하고 싶었으므로 Opened이벤트를 처리 한 다음 이렇게했습니다.

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

해킹이지만 작동했습니다.

아마도 유사하게 Closed이벤트를 처리하고 다시 열도록 지시하여 계속 표시 할 수 있습니다.


도구 설명 대신 사용할 수 HasContent라는 속성이있다
benPearce

2

완전성을 위해 : 코드에서 다음과 같이 보입니다.

ToolTipService.SetShowDuration(element, 60000);

0

또한 ToolTip에 다른 컨트롤을 추가하려는 경우 ToolTip 자체가 포커스를받을 수 있으므로 포커스를받을 수 없습니다. 그래서 micahtan이 말했듯이, 당신의 베스트 샷은 Popup입니다.


0

동일한 코드로 문제가 해결되었습니다.

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


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

그것은 나를 위해 일하고 있습니다. 이 줄을 클래스 생성자에 복사합니다.


3
이 복사 및이 두 번째로 upvotes으로 허용 대답 붙여 넣기입니다
CodingYourLife
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.