질문하기질문하기
 

답변됨Scrolling Marquee

  • 2008년 1월 2일 수요일 오후 3:48Jonathan.Peppers 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     

    I need to create a scrolling Marquee that only scrolls when the text would be trimmed. (CharacterEllipsis is used)

     

    So I subclassed Textblock, and was going to setup a DoubleAnimation that would accomplish this.  But how do I tell when the text would be trimmed?  There doesn't seem to be a IsTextTrimmed property... that would have been just too easy.

     

    Would a better solution be to derive from control, and override OnRender?  Then I could maybe use the FormattedText class to get all the extra functionality that TextBlock already has built in.

     

    A third, and maybe easiest way would be to do this from a Style and a Trigger and I wouldn't subclass anything.  But is this too low level to accomplish this way?

     

    I'm looking for the "best" solution here (not wanting to re-invent the wheel), so any help would greatly be appreciated.

답변

  • 2008년 1월 4일 금요일 오전 8:53Marco Zhou 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     답변됨
    I've mocked up with a TextBlock derivative:
    public class TextBlockEx : TextBlock
    {
    public TextBlockEx() : base()
    {
    this.LayoutUpdated += delegate
    {
    CultureInfo cultureInfo = this.Language.GetEquivalentCulture();
    FormattedText ft = new FormattedText(
    this.Text,
    cultureInfo,
    this.FlowDirection,
    new Typeface(
    this.FontFamily,
    this.FontStyle,
    this.FontWeight,
    this.FontStretch,
    null),
    this.FontSize,
    this.Foreground);
    base.SetValue(IsTextTrimmedPropertyKey, ft.Width > this.ActualWidth);
    base.SetValue(TextTrimmedWidthPropertyKey, ft.Width - this.ActualWidth);
    base.SetValue(TextExtentWidthPropertyKey, ft.Width);
    };
    }

    private static readonly DependencyPropertyKey IsTextTrimmedPropertyKey = DependencyProperty.RegisterReadOnly(
    "IsTextTrimmed",
    typeof(Boolean),
    typeof(TextBlockEx),
    new FrameworkPropertyMetadata(false));

    public static readonly DependencyProperty IsTextTrimmedProperty = IsTextTrimmedPropertyKey.DependencyProperty;


    public Boolean IsTextTrimmed
    {
    get { return (Boolean)GetValue(IsTextTrimmedProperty); }
    }

    private static readonly DependencyPropertyKey TextTrimmedWidthPropertyKey = DependencyProperty.RegisterReadOnly(
    "TextTrimmedWidth",
    typeof(Double),
    typeof(TextBlockEx),
    new FrameworkPropertyMetadata(0.0d));

    public static readonly DependencyProperty TextTrimmedWidthProperty = TextTrimmedWidthPropertyKey.DependencyProperty;


    public Double TextTrimmedWidth
    {
    get { return (Double)GetValue(TextTrimmedWidthProperty); }
    }

    private static readonly DependencyPropertyKey TextExtentWidthPropertyKey = DependencyProperty.RegisterReadOnly(
    "TextExtentWidth",
    typeof(Double),
    typeof(TextBlockEx),
    new FrameworkPropertyMetadata(0.0d));

    public static readonly DependencyProperty TextExtentWidthProperty = TextExtentWidthPropertyKey.DependencyProperty;


    public Double TextExtentWidth
    {
    get { return (Double)GetValue(TextExtentWidthProperty); }
    }
    }

    I have defined three readonly dependency properties aka TextExtentWidth, TextTrimmedWidth, and IsTextTrimmed, and calculate their values in the LayoutUpdated event handler, with those three properties at hand, you should be able to properly implement the animation logic using bare-bones DoubleAnimationSleep.

    Hope this helps

모든 응답

  • 2008년 1월 3일 목요일 오후 7:33Jonathan.Peppers 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     

     

    Well, I ended up subclassing Canvas, adding a private Textblock to it, and animating Canvas.Left.  However, I couldn't get my DoubleAnimationUsingKeyFrames to work out how I wanted (I could not get a constant speed that would repeat forever).

     

    Here should be my keyframes in Plain English:

     

    Wait 1 second

    Do

    Scroll left until the Textblock is off screen

    DiscreteDoubleKeyFrame move the block's Canvas.Left to the Canvas's Width

    Scroll until the Textblock's Canvas.Left is 0

    Repeat while Visible

     

    The catch is the speed my textblock moves should be a constant now matter how long the TextBlock is, and this speed ratio needs to be a DependencyProperty you can set.

     

    Now, I rebuild my animation dynamically when visible or the length of the Textblock changes, so the issue is getting my KeyTimes right.

     

    I tried several methods, even calculating the time by hand, using Keytime.Uniform or Keytime.Paced, etc.

     

    Any ideas?

     

  • 2008년 1월 4일 금요일 오전 8:53Marco Zhou 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     답변됨
    I've mocked up with a TextBlock derivative:
    public class TextBlockEx : TextBlock
    {
    public TextBlockEx() : base()
    {
    this.LayoutUpdated += delegate
    {
    CultureInfo cultureInfo = this.Language.GetEquivalentCulture();
    FormattedText ft = new FormattedText(
    this.Text,
    cultureInfo,
    this.FlowDirection,
    new Typeface(
    this.FontFamily,
    this.FontStyle,
    this.FontWeight,
    this.FontStretch,
    null),
    this.FontSize,
    this.Foreground);
    base.SetValue(IsTextTrimmedPropertyKey, ft.Width > this.ActualWidth);
    base.SetValue(TextTrimmedWidthPropertyKey, ft.Width - this.ActualWidth);
    base.SetValue(TextExtentWidthPropertyKey, ft.Width);
    };
    }

    private static readonly DependencyPropertyKey IsTextTrimmedPropertyKey = DependencyProperty.RegisterReadOnly(
    "IsTextTrimmed",
    typeof(Boolean),
    typeof(TextBlockEx),
    new FrameworkPropertyMetadata(false));

    public static readonly DependencyProperty IsTextTrimmedProperty = IsTextTrimmedPropertyKey.DependencyProperty;


    public Boolean IsTextTrimmed
    {
    get { return (Boolean)GetValue(IsTextTrimmedProperty); }
    }

    private static readonly DependencyPropertyKey TextTrimmedWidthPropertyKey = DependencyProperty.RegisterReadOnly(
    "TextTrimmedWidth",
    typeof(Double),
    typeof(TextBlockEx),
    new FrameworkPropertyMetadata(0.0d));

    public static readonly DependencyProperty TextTrimmedWidthProperty = TextTrimmedWidthPropertyKey.DependencyProperty;


    public Double TextTrimmedWidth
    {
    get { return (Double)GetValue(TextTrimmedWidthProperty); }
    }

    private static readonly DependencyPropertyKey TextExtentWidthPropertyKey = DependencyProperty.RegisterReadOnly(
    "TextExtentWidth",
    typeof(Double),
    typeof(TextBlockEx),
    new FrameworkPropertyMetadata(0.0d));

    public static readonly DependencyProperty TextExtentWidthProperty = TextExtentWidthPropertyKey.DependencyProperty;


    public Double TextExtentWidth
    {
    get { return (Double)GetValue(TextExtentWidthProperty); }
    }
    }

    I have defined three readonly dependency properties aka TextExtentWidth, TextTrimmedWidth, and IsTextTrimmed, and calculate their values in the LayoutUpdated event handler, with those three properties at hand, you should be able to properly implement the animation logic using bare-bones DoubleAnimationSleep.

    Hope this helps
  • 2008년 1월 4일 금요일 오후 10:12Jonathan.Peppers 사용자 메달사용자 메달사용자 메달사용자 메달사용자 메달
     
    Thanks! that points me in the right direction.