Formula una domandaFormula una domanda
 

Con rispostaScrolling Marquee

  • mercoledì 2 gennaio 2008 15.48Jonathan.Peppers Medaglie utenteMedaglie utenteMedaglie utenteMedaglie utenteMedaglie utente
     

    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.

Risposte

  • venerdì 4 gennaio 2008 8.53Marco Zhou Medaglie utenteMedaglie utenteMedaglie utenteMedaglie utenteMedaglie utente
     Con risposta
    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

Tutte le risposte

  • giovedì 3 gennaio 2008 19.33Jonathan.Peppers Medaglie utenteMedaglie utenteMedaglie utenteMedaglie utenteMedaglie utente
     

     

    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?

     

  • venerdì 4 gennaio 2008 8.53Marco Zhou Medaglie utenteMedaglie utenteMedaglie utenteMedaglie utenteMedaglie utente
     Con risposta
    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
  • venerdì 4 gennaio 2008 22.12Jonathan.Peppers Medaglie utenteMedaglie utenteMedaglie utenteMedaglie utenteMedaglie utente
     
    Thanks! that points me in the right direction.