Continuous text Ticker in WPF
Asked Answered
D

3

6

Gaurang Gaurang Gaurang Gaurang Gaurang Gaurang Gaurang Gaurang Gaurang Gaurang Gaurang

I am working in WPF to create a text ticker. I am able to move the text from right to left forever but my problem is, that I want to move the same text seamlessly to create the above effect(Just like the stock exchange ticker). The above text must move endlessly.

How can I achieve it?

Diencephalon answered 21/2, 2014 at 8:41 Comment(6)
so your text will be just "Gaurang" and it should be moved as marquee right ? You can use any of this links 1) jobijoy.blogspot.in/2008/08/…, 2) weblogs.asp.net/razan/archive/2009/10/01/…, 3) codeproject.com/Articles/48267/…Knighton
Hi Milan. yes my text is Gaurang and it should be moved right but it should be endless text scrolling without any gap in between.Diencephalon
Do you mean it should be repeated if no other text exists in the list ?Knighton
Yes it must be repeatedDiencephalon
You can use carousel control and make it continue, link: codeproject.com/Articles/181835/WPF-Carousel-ControlKnighton
Ok. I will give it a try. It would be great if you give me an idea that won't make use of any third party tool if its possible.Diencephalon
S
5

So from reading your question i'm not really sure what you want. Do you want a text, that scrolls out of the textbox, and starts over, like most marquee controls/functions.

Or do you want some text that runs over and over in your textbox, filling it out from start till end? and then with a given loop that is undectectable? :)

Code behind:

//Single line animation.

private void LeftToRightMarqueeOnTextBox()
{
  string Copy = " "+TextBoxMarquee.Text;
  double TextGraphicalWidth = new FormattedText(TextBoxMarquee.Text, System.Globalization.CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(TextBoxMarquee.FontFamily.Source), TextBoxMarquee.FontSize, TextBoxMarquee.Foreground).WidthIncludingTrailingWhitespace;
  //BorderTextBoxMarquee.Width = TextGraphicalWidth + 5;

  ThicknessAnimation ThickAnimation = new ThicknessAnimation();
  ThickAnimation.From = new Thickness(TextBoxMarquee.ActualWidth, 0, 0, 0);
  ThickAnimation.To = new Thickness(-TextGraphicalWidth, 0, 0, 0);
  ThickAnimation.RepeatBehavior = RepeatBehavior.Forever;
  ThickAnimation.Duration = new Duration(TimeSpan.FromSeconds(3));
  TextBoxMarquee.BeginAnimation(TextBox.PaddingProperty, ThickAnimation);
}

OR

//Sentence Repeat animation with no gaps.

string Copy = " "+TextBoxMarquee.Text;
  double TextGraphicalWidth = new FormattedText(Copy, System.Globalization.CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(TextBoxMarquee.FontFamily.Source), TextBoxMarquee.FontSize, TextBoxMarquee.Foreground).WidthIncludingTrailingWhitespace;
  double TextLenghtGraphicalWidth = 0;
  //BorderTextBoxMarquee.Width = TextGraphicalWidth + 5;
  while (TextLenghtGraphicalWidth < TextBoxMarquee.ActualWidth)
  {
    TextBoxMarquee.Text += Copy;
    TextLenghtGraphicalWidth = new FormattedText(TextBoxMarquee.Text, System.Globalization.CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(TextBoxMarquee.FontFamily.Source), TextBoxMarquee.FontSize, TextBoxMarquee.Foreground).WidthIncludingTrailingWhitespace;
  }
  TextBoxMarquee.Text += " "+TextBoxMarquee.Text;
  ThicknessAnimation ThickAnimation = new ThicknessAnimation();
  ThickAnimation.From = new Thickness(0, 0, 0, 0);
  ThickAnimation.To = new Thickness(-TextGraphicalWidth, 0, 0, 0);
  ThickAnimation.RepeatBehavior = RepeatBehavior.Forever;
  ThickAnimation.Duration = new Duration(TimeSpan.FromSeconds(2));
  TextBoxMarquee.BeginAnimation(TextBox.PaddingProperty, ThickAnimation);

XAML:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Canvas ClipToBounds="True" Name="canMain" Background="Transparent">
        <Grid Width="{Binding ElementName=canMain, Path=ActualWidth}" >
            <Grid.ColumnDefinitions>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Name="TextBlockMarquee" Text="This is my animated text" />
            <Border Grid.Row="1" BorderBrush="Black" BorderThickness="1">
                <TextBox ClipToBounds="True" Name="TextBoxMarquee" Text="lars er en god skakspiller, der tænker længere end de andre" BorderBrush="Transparent"/>
            </Border>
        </Grid>
    </Canvas>
</Grid>

Basically ignore most of the XAML. Whats important is the lenght of the Text in the Textbox. Havn't found a generic solution, thats why my From Thickness is number based.

But just had to be sure that this was what you were looking for :)

EDIT/UPDATE:

So try it out now, i've updated the code.. Hopefully it works, but from a few test it seemed like it :) Only thing that you need to be sure of is that the entire textbox is filled out, then i'm doing a copy of it, and i'll loop the two text from the strings graphical lenght :)(

EDIT/UPDATE: I've added my final solutions hope this was of any help.

EDIT/Update

Forgot to update my Repeat solution so it didn't cut off and make the loops visible.. Done now :)

Sequacious answered 21/2, 2014 at 10:16 Comment(19)
Yup I want the second option. I want some text that runs over and over in my textblock, filling it out from start till end and scroll itDiencephalon
Yes thats what I was looking forDiencephalon
The problem with this is there are alot of variables to take into consideration. Fontsize, fontfamily, textboxwidth, text.lenght and so on. So i'm not sure what you are putting inside your textbox, but i think you it's going to be a bit complicated to managed if the text changes or something else changes that has something to do with the textbox. If everything is static, you could pretty much just do what i just did. :) But i'll keep looking for a while to see what I can come up with :)Sequacious
Ok. Ya that's the issue the content would change frequently. It comes from the server. Thanks for replyDiencephalon
another question. Is your textbox stretched across the window, or only a filling a small % of the width. and a last question, the input is that one word repeated or actualy sentences?Sequacious
It will be stretched across the window.Diencephalon
Input will be mostly Welcome Company Name... It may be sentences in rare cases.Diencephalon
I think i did it.. :D This should work perfectly! :D hopefully.. Im gonna update my comment further up :)Sequacious
I put the string Welcome to IndiaDiencephalon
Okay, so this is where you have a small text, that you want to show so we need to do something about the widt of the textbox/border in order to show only welcome to india. give me a few minutes, still however do you want to resize the textbox so it looks like this [Welcome To india] or like this [Welcome to india______]Sequacious
Its fine like this:[Welcome to india______]Diencephalon
Updating again.. so like this? or ?Sequacious
My biggest problem is to make out what looks best.. The single line being moved from side to side, or when you actually have the sentence overrunning it self. Because... If it's a sentence, it somehow make sense if it fills the entire textbox, however, if it's only a few words it looks stupid if it's on repeat.. Then you rather want to have the single text version that gets animated from one side to another, and then starts over.. but i don't know it's hard.. I'll provide you both my solutions, then you can just adjust to what you like best :)Sequacious
One last thing i forgot to say which i just realised.. After all this is done, you also have to take the duration into consideration... If it's a long text, you'll want to reduce the speed of the text. and if it's a short text you'd like to increase the duration. However, this shouldn't be to hard to add :) Good luckSequacious
Hi Max.. I implemented your solution and it worked great. Thanks a lot for the solution.Diencephalon
Hi Max.. Can I do the same thing using a TextBlock control?Diencephalon
@Gaurang.. Yes :) The animation is made on the Padding property, so if the element is containing that property, you should be able to do it :)Sequacious
@Diencephalon I just realised a TextBlock can't go into minus padding, Which means you would have to change the property you are working on to margin, so the entire textblock leaves the border. A minor change, shouldn't be to difficult, I just don't have time right now to provide an example.. Maybe tomorrow..Sequacious
@Diencephalon forget what I just said.. Just change the Textbox.PaddingProperty to TextBlock.MarginProperty, and it's working like before, and add a textblock instead of a textbox :)Sequacious
D
4

I would create multiple ContentControls (or whatever controls you want to use) and put them in a StackPanel with horizontal direction. The number of ContentControls depends on the size of the content. Therefore, I would create one ContentControl, assign the content, and then call Measure(...) on it to determine the size it needs. Depending on the size of the window or parent control, you can calculate how many controls you need to create to fill the entire space. This would look something like this:

Initial state (1):  +------------- Parent Control -------------+
                    |                                          |
                    |+---------+ +---------+ +---------+ +-----|---+ +---------+
                    || Gaurang | | Gaurang | | Gaurang | | Gaur|ng | | Gaurang |
                    |+---------+ +---------+ +---------+ +-----|---+ +---------+
                    |                                          |^^^^^^^^^^^^^^^^
                    +------------------------------------------+  not visible!

Then I would put the StackPanel with the ContentControls into a Canvas and animate the StackPanel's Canvas.Left property, so that it moves into the desired direction.

Now the problem is that the end of the StackPanel will move into the visible area and there will be no more ContentControl to show:

Bad state (2):      +------------- Parent Control -------------+
                    |                                          |
+---------+ +-------|-+ +---------+ +---------+ +---------+    |
| Gaurang | | Gauran| | | Gaurang | | Gaurang | | Gaurang |    |
+---------+ +-------|-+ +---------+ +---------+ +---------+    |
^^^^^^^^^^^^^^^^^^^^|                                          |
     not visible    +------------------------------------------+
                                                           ^^^^
                                                            BAD

You can fix this by restricting the animation of the StackPanel's Canvas.Left property, so that it only moves until the first ContentControl was moved out of the visible area:

Final state (3):    +------------- Parent Control -------------+
                    |                                          |
         +---------+|+---------+ +---------+ +---------+ +-----|---+
         | Gaurang ||| Gaurang | | Gaurang | | Gaurang | | Gaur|ng |
         +---------+|+---------+ +---------+ +---------+ +-----|---+
                    |                                          |
                    +------------------------------------------+

Once this state is reached, the animation should start from the beginning, i.e. go back to the initial state (1). This way, you will always animate between state (1) and state (3). Since all ContentControls have the same size, the user gets the impression of an infinitely moving animation. Of course, the animation should be configured to repeat infinitely.

Note: I did not test this, but I think it should work. Now I did test it, and it works. Here is my test code:

<Canvas>
    <StackPanel x:Name="stack" Orientation="Horizontal">
        <StackPanel.Triggers>
            <EventTrigger RoutedEvent="Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation
                            Storyboard.TargetProperty="(Canvas.Left)"
                            From="0" To="-68"
                            FillBehavior="Stop" RepeatBehavior="Forever"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </StackPanel.Triggers>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
        <ContentControl Content="Gaurang" Margin="4" Width="60"/>
    </StackPanel>
</Canvas>

Paste this into a blank WPF Window and run it. You can increase the size of the window to see what really happens - the animation only moves by one ContentControl and then starts from the beginning.

Note that the To="-68" is calculated using Width + Margin.Left + Margin.Right. In your case, you would have to add the ContentControls manually in code-behind, determine their width and set the animation's To property accordingly.

Denotation answered 21/2, 2014 at 11:33 Comment(2)
this does not work correctly. for example if you do gaurang0, gaurang1 as the text, gaurang0 is always at the left and never scrolls from far fight.Langill
@DermFrench: The original question was about repeating the same text again and again. Of course, this solution does not work for different text labels.Denotation
C
0

I created an application to display RSS feeds as a ticker that moves right to left just like a stock ticker. It should be trivial to modify it to be a stock ticker instead. RumorMill4

The link has a brief tutorial and all the source code, but the one thing you will need to know is this ticker works off a Queue, so once an item has scrolled off it is De-queued. At that time you could check if the data is still relevant and update it then add it back to the queue for display.

Unfortunately this implementation does not support DataBinding so you cannot adjust the values while the ticker is currently moving the item. (wrote it years ago, and RSS feeds don't change like stocks do, so wasn't a priority.)

Cisneros answered 9/8, 2016 at 22:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.