I created Marquee Textblock control in WPF for my app but it was not showing the entire text. I tried to solve where the problem is but i am unable to solve.
Created Marquee textblock control xaml code is
UserControl x:Class="Andhrajyo.MarqueeTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480"
Grid x:Name="LayoutRoot"
<Canvas x:Name="canvas" Background="Transparent" Width="{Binding Width}" Height="{Binding Height}">
<Canvas.Clip>
RectangleGeometry RadiusX="5" RadiusY="5" Rect="400, 400, 400, 400"
</Canvas.Clip>
TextBlock x:Name="textBlock1"
Height="{Binding Height}"
Width="{Binding Width}"
TextWrapping="NoWrap"
Foreground="{Binding Foreground}"
Text="{Binding Text}"
FontSize="{Binding MFontSize}"
</Canvas>
/Grid
/UserControl
Marquee Textblock.xaml.cs is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Andhrajyo
{
public partial class MarqueeTextBlock : UserControl
{
// storyboard
Storyboard storyboard;
// offset when textBlock1 is long, because user want to see smooth scrolling
private double offset =0;
// default offset
private double defaultOffset =100;
// default velocity
int velocity = 0;
// whether control has beed loaded
// because it's when control is loaded do we start marquee
bool isLoaded = false;
public MarqueeTextBlock()
{
InitializeComponent();
Loaded += MarqueeTextBlock_Loaded;
Unloaded += MarqueeTextBlock_Unloaded;
}
// unload event
void MarqueeTextBlock_Unloaded(object sender, RoutedEventArgs e)
{
// stop marquee when control is unloaded
StopMarquee();
}
// set data context in Loaded
void MarqueeTextBlock_Loaded(object sender, RoutedEventArgs e)
{
if (!isLoaded)
{
// control is loaded
isLoaded = true;
LayoutRoot.DataContext = this;
// resize the clipping
Rect rect = new Rect(0,0, canvas.ActualWidth, canvas.ActualHeight);
RectangleGeometry reo = new RectangleGeometry();
reo.Rect = rect;
this.canvas.Clip = reo;
// always vertical alignment
ChangeOffsetTop();
// this is OK for marquee to start
StartMarquee();
}
else
{
// just run it, after user come to this page again
StartMarquee();
}
}
public void StartMarquee()
{
// first stop all marquee
StopMarquee();
if (ShouldStartMarquee())
{
// change offset
ChangeOffsetLeft(true);
DoAnimationFirst();
}
else
{
// change offset
ChangeOffsetLeft(false);
}
}
public void StopMarquee()
{
if (storyboard != null)
{
storyboard.Stop();
}
}
bool ShouldStartMarquee()
{
return textBlock1.ActualWidth > LayoutRoot.ActualWidth;
}
// after
void storyboard_Completed(object sender, EventArgs e)
{
DoAnimationAfter();
// remeber to unsubscribe
storyboard.Completed += storyboard_Completed;
}
////////////////////////////////////////////////////////////////////////////
// calculate offset
void ChangeOffsetLeft(bool isLong)
{
if (isLong)
{
offset = defaultOffset;
Canvas.SetLeft(textBlock1, offset);
}
else
{
offset = (canvas.ActualWidth - textBlock1.ActualWidth)/2;
Canvas.SetLeft(textBlock1, offset);
}
}
// center vertical
void ChangeOffsetTop()
{
double topOffset = (canvas.ActualHeight - textBlock1.ActualHeight) / 2;
Canvas.SetTop(textBlock1, topOffset);
}
int CalculateDurationFirst()
{
int duration = 45000;
return duration;
}
int CalculateDurationAfter()
{
int duration = 40000;
return duration;
}
void DoAnimationFirst()
{
storyboard = new Storyboard();
TranslateTransform trans = new TranslateTransform() { X = 5.0, Y = 1.0 };
textBlock1.RenderTransformOrigin = new Point(0.5,0.5);
textBlock1.RenderTransform = trans;
// we must calculate the Duration
DoubleAnimation moveAnim = new DoubleAnimation();
int durationFirst = CalculateDurationFirst();
moveAnim.Duration = TimeSpan.FromMilliseconds(durationFirst);
moveAnim.From = 0;
moveAnim.To = -textBlock1.ActualWidth - offset;
Storyboard.SetTarget(moveAnim, textBlock1);
Storyboard.SetTargetProperty(moveAnim, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
// subscribe to Completed event
storyboard.Completed += new EventHandler(storyboard_Completed);
storyboard.Children.Add(moveAnim);
storyboard.FillBehavior = FillBehavior.HoldEnd;
storyboard.Begin();
}
void DoAnimationAfter()
{
storyboard = new Storyboard();
TranslateTransform trans = new TranslateTransform() { X = 5.0, Y = 1.0 };
textBlock1.RenderTransformOrigin = new Point(0.5, 0.5);
textBlock1.RenderTransform = trans;
// we must calculate the Duration
DoubleAnimation moveAnim = new DoubleAnimation();
int durationAfter = CalculateDurationAfter();
moveAnim.Duration = TimeSpan.FromMilliseconds(durationAfter);
moveAnim.From = canvas.ActualWidth;
moveAnim.To = -textBlock1.ActualWidth - offset;
Storyboard.SetTarget(moveAnim, textBlock1);
Storyboard.SetTargetProperty(moveAnim, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
storyboard.Children.Add(moveAnim);
storyboard.RepeatBehavior = RepeatBehavior.Forever;
storyboard.FillBehavior = FillBehavior.HoldEnd;
storyboard.Begin();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dependency property
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MarqueeTextBlock), null);
public string Text
{
get { return (string)this.GetValue(TextProperty); }
set
{
this.SetValue(TextProperty, value);
// this doesnot marquee for the first time
// because textBlock1.ActualWidth is 0 !!
if (isLoaded)
{
StartMarquee();
}
}
}
public static readonly DependencyProperty MFontSizeProperty = DependencyProperty.Register("MFontSize",
typeof(int), typeof(MarqueeTextBlock), null);
public int MFontSize
{
get { return (int)this.GetValue(MFontSizeProperty); }
set
{
this.SetValue(MFontSizeProperty, value);
}
}
public static readonly DependencyProperty MTextTrimProperty = DependencyProperty.Register("MTextTrim",
typeof(String), typeof(MarqueeTextBlock), null);
public String MTextTrim
{
get { return (String)this.GetValue(MFontSizeProperty); }
set
{
this.SetValue(MTextTrimProperty, value);
}
}
}
}
My application code which uses the marquee textblock control is
controls2:marqueetextblock x:name="txtT" xmlns:x="#unknown" xmlns:controls2="#unknown">
MFontSize="25"
Width="1000"
Height="80" Margin="20,-10,0,0"
/>
./controls2:marqueetextblock
the text property was set in the code behind
after executing the marquee textblock is not showing the entire text the last text is missing..
the text is long of more than 500 characters
please help me.