Odeslat dotazOdeslat dotaz
 

OdpovědětScrolling Marquee

  • 2. ledna 2008 15:48Jonathan.Peppers Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    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.

Odpovědi

  • 4. ledna 2008 8:53Marco Zhou Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     Odpovědět
    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

Všechny reakce

  • 3. ledna 2008 19:33Jonathan.Peppers Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

     

    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?

     

  • 4. ledna 2008 8:53Marco Zhou Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     Odpovědět
    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
  • 4. ledna 2008 22:12Jonathan.Peppers Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Thanks! that points me in the right direction.