using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using JustinAngelNet.SilverlightRTL.RTL;
using JustinAngelNet.Silverlight.Framework;
using NBiDi.Extensions;
namespace JustinAngelNet.SilverlightRTL.RTL
{
public class RTLExtender : ControlExtenderBase
{
public RTLExtender()
: base()
{
this.BaseLoaded += new EventHandler(RTLExtender_Loaded);
}
void RTLExtender_Loaded(object sender, EventArgs e)
{
if (this.Enabled)
{
if (!HasCanvasesOrTextBlocks)
{
SearchEntireXAMLFileForTextBlcoksAndRTLThem();
}
else
{
if (HasCanvases)
{
SearchTargetNonExcludedCanvasesForTextBlocksAndRTLThem();
}
if (HasTextBlocks)
{
SearchNonExcludedTargetTextBlocksAndRTLThem();
}
}
}
}
private void SearchEntireXAMLFileForTextBlcoksAndRTLThem()
{
List<TextBlock> textBlocksOnCanvas = new List<TextBlock>();
IterateOverCanvasAndFindTextBlocksToRTL(this.RootCanvas, textBlocksOnCanvas);
foreach (TextBlock textBlockOnCanvas in textBlocksOnCanvas)
if (!ExcludedTextBlocks.Contains(textBlockOnCanvas))
ChangeTextBlockToRTL(textBlockOnCanvas as TextBlock, false);
}
private void SearchNonExcludedTargetTextBlocksAndRTLThem()
{
foreach (TextBlock targetTextBlock in TargetTextBlocks)
{
if (!ExcludedTextBlocks.Contains(targetTextBlock))
ChangeTextBlockToRTL(targetTextBlock, false);
}
}
private void SearchTargetNonExcludedCanvasesForTextBlocksAndRTLThem()
{
List<TextBlock> textBlocksOnCanvas = new List<TextBlock>();
foreach (Canvas targetCanvas in TargetCanvases)
{
if (!ExcludedCanvases.Contains(targetCanvas))
IterateOverCanvasAndFindTextBlocksToRTL(targetCanvas, textBlocksOnCanvas);
}
foreach (TextBlock textBlockOnCanvas in textBlocksOnCanvas)
if (!ExcludedTextBlocks.Contains(textBlockOnCanvas))
ChangeTextBlockToRTL(textBlockOnCanvas as TextBlock, false);
}
private static Dictionary<TextBlock, List<TextBlock>> _RTLTextBlockForNonRTLTextBlock =
new Dictionary<TextBlock, List<TextBlock>>();
public static Dictionary<TextBlock, List<TextBlock>> RTLTextBlockForNonRTLTextBlock
{
get { return RTLExtender._RTLTextBlockForNonRTLTextBlock; }
set { RTLExtender._RTLTextBlockForNonRTLTextBlock = value; }
}
private static List<TextBlock> textBlocksAllreadyRTLed = new List<TextBlock>();
private void ChangeTextBlockToRTL(TextBlock textBlockToRTL, bool Force)
{
if (string.IsNullOrEmpty(textBlockToRTL.Text))
return;
if ((CheckTextBlockNotAllreadyDone(textBlockToRTL)
&& TextBlockDoesNotHaveAnyAnimations(textBlockToRTL, Force)
&& TextBlockDoesNotHaveRotateTransform(textBlockToRTL, Force))
|| Force)
DoRTLOnTextBlock(textBlockToRTL);
}
private bool TextBlockDoesNotHaveRotateTransform(TextBlock textBlockToRTL, bool force)
{
RotateTransform rotate = null;
if (textBlockToRTL.RenderTransform is RotateTransform)
rotate = textBlockToRTL.RenderTransform as RotateTransform;
if (textBlockToRTL.RenderTransform is TransformGroup)
foreach (Transform curTransformToCheckIsRotateTransformAndCheckItsAngle in ((TransformGroup)textBlockToRTL.RenderTransform).Children)
if (curTransformToCheckIsRotateTransformAndCheckItsAngle is RotateTransform)
rotate = curTransformToCheckIsRotateTransformAndCheckItsAngle as RotateTransform;
if (rotate != null)
if (rotate.Angle != 0.0)
ThrowException(force, GetRotateAngleErrorMessage(textBlockToRTL, rotate));
return true;
}
private string GetRotateAngleErrorMessage(TextBlock textBlockToRTL, RotateTransform rotateThatIsNotZeroAngle)
{
return
string.Format("TextBlock {0} should not have a RotateTransform angle other then 0 becuase it interfers with the RTLExtender. Currently it has an RotateTransform angle of {1} Please set it back to 0 and use a Loaded Animation to rotate the TextBlock's Canvas", textBlockToRTL.Name, rotateThatIsNotZeroAngle.Angle.ToString());
}
private bool TextBlockDoesNotHaveAnyAnimations(TextBlock textBlockToRTL, bool Force)
{
List<string> AnimationsNameOnTextBlock = new List<string>();
IterateOverCanvasAndCheckIfHasAnimatiosOnTextBlock(textBlockToRTL, AnimationsNameOnTextBlock, this.RootCanvas);
if (AnimationsNameOnTextBlock.Count != 0)
ThrowException(Force, GetErrorMessageForAnimbationAndTextBlockToRTL(AnimationsNameOnTextBlock, textBlockToRTL));
return true;
}
private void ThrowException(bool ForceNotThrowException, string errorMsg)
{
if (ForceNotThrowException)
System.Diagnostics.Debug.WriteLine(errorMsg);
else
throw new SilverlightToolboxException(errorMsg);
}
private string GetErrorMessageForAnimbationAndTextBlockToRTL(List<string> animationsThatThrowErrorOn, TextBlock textBlockToRTL)
{
string AnimationsName = string.Empty;
foreach (string curAnimationToAddToError in animationsThatThrowErrorOn)
{
if (!string.IsNullOrEmpty(curAnimationToAddToError))
AnimationsName += curAnimationToAddToError + " ,";
}
if (string.IsNullOrEmpty(AnimationsName))
AnimationsName = "Unknown";
return
string.Format("TextBlock {0} should not have any animations on it because it will be replaced by the RTLExtender. Animations names: {1}. Please place the TextBlock in a canvas (Right Click --> Group --> Canvas) and point all animations to the Canvas.", textBlockToRTL.Name, AnimationsName);
}
private void IterateOverCanvasAndCheckIfHasAnimatiosOnTextBlock(TextBlock textBlockToRTL, List<string> AnimationsNameOnTextBlock, UIElement objectToIterateOver)
{
IterateOverResourcesAndTriggersAndfindAnimations(textBlockToRTL, AnimationsNameOnTextBlock, objectToIterateOver);
IterateOverCanvasChildren(textBlockToRTL, AnimationsNameOnTextBlock, objectToIterateOver);
}
private void IterateOverCanvasChildren(TextBlock textBlockToRTL, List<string> AnimationsNameOnTextBlock, UIElement objectToIterateOver)
{
Canvas childCanvasToIterateOver = objectToIterateOver as Canvas;
if (childCanvasToIterateOver != null)
{
foreach (Visual visualToIterateOVer in childCanvasToIterateOver.Children)
if (visualToIterateOVer is UIElement)
IterateOverCanvasAndCheckIfHasAnimatiosOnTextBlock(textBlockToRTL, AnimationsNameOnTextBlock,
(UIElement)visualToIterateOVer);
}
}
private static void IterateOverResourcesAndTriggersAndfindAnimations(TextBlock textBlockToRTL, List<string> AnimationsNameOnTextBlock, UIElement objectToIterateOver)
{
foreach (DependencyObject curObjectToCheckNotSetOnTextBlock in objectToIterateOver.Resources)
{
CheckForAnimatiosAndStoryBoard(textBlockToRTL, AnimationsNameOnTextBlock, curObjectToCheckNotSetOnTextBlock);
}
foreach (EventTrigger curObjectToCheckNotSetOnTextBlock in objectToIterateOver.Triggers)
{
foreach (BeginStoryboard beginStoryboard in curObjectToCheckNotSetOnTextBlock.Actions)
{
CheckForAnimatiosAndStoryBoard(textBlockToRTL, AnimationsNameOnTextBlock, beginStoryboard.Storyboard);
}
}
}
private static void CheckForAnimatiosAndStoryBoard(TextBlock textBlockToRTL, List<string> AnimationsNameOnTextBlock, DependencyObject curObjectToCheckNotSetOnTextBlock)
{
Animation curAnimation = curObjectToCheckNotSetOnTextBlock as Animation;
if (curAnimation != null)
{
if (curAnimation.GetValue(Storyboard.TargetNameProperty).ToString() == textBlockToRTL.Name)
AnimationsNameOnTextBlock.Add(curAnimation.Name);
}
Storyboard curStoryboard = curObjectToCheckNotSetOnTextBlock as Storyboard;
if (curStoryboard != null)
{
foreach (Animation timelineToCheckChildren in curStoryboard.Children)
{
if (timelineToCheckChildren.GetValue(Storyboard.TargetNameProperty).ToString() == textBlockToRTL.Name)
{
AnimationsNameOnTextBlock.Add(timelineToCheckChildren.Name);
if (!AnimationsNameOnTextBlock.Contains(curStoryboard.Name))
AnimationsNameOnTextBlock.Add(curStoryboard.Name);
}
}
}
}
private void DoRTLOnTextBlock(TextBlock textBlockToRTL)
{
if (textBlockToRTL.TextWrapping == TextWrapping.NoWrap)
{
//TextBlock newTextBlock = SilverlightExtensions.Clone<TextBlock>(textBlockToRTL);
textBlockToRTL.Text = NBidi.NBidi.LogicalToVisual(textBlockToRTL.Text);
//Canvas textBlockParent = (Canvas) textBlockToRTL.Parent;
//textBlockParent.Children.Remove(textBlockToRTL);
RTLTextBlockForNonRTLTextBlock[textBlockToRTL] = new List<TextBlock>(new TextBlock[] { textBlockToRTL });
}
else // (textBlockToRTL.TextWrapping != TextWrapping.NoWrap)
{
List<TextBlock> TextBlocksAttachedToTextBlockParent = SilverlightAlignmenetParagraphsToRowsAlgorithem.RtlTextBlockToWrappingScenarios(textBlockToRTL, ForceAllParagraphsAsRTL);
foreach (TextBlock textBlocksAttachedToCanvas in TextBlocksAttachedToTextBlockParent)
{
textBlocksAllreadyRTLed.Add(textBlocksAttachedToCanvas);
}
RTLTextBlockForNonRTLTextBlock[textBlockToRTL] = TextBlocksAttachedToTextBlockParent;
}
}
private static bool CheckTextBlockNotAllreadyDone(TextBlock textBlockToRTL)
{
if (!textBlocksAllreadyRTLed.Contains(textBlockToRTL))
{
textBlocksAllreadyRTLed.Add(textBlockToRTL);
return true;
}
return false;
}
public void RTLCanvas(Canvas canvasToRTL)
{
RTLCanvas(canvasToRTL, ForceAllParagraphsAsRTL);
}
public void RTLCanvas(Canvas canvasToRTL, bool forceRTL)
{
List<TextBlock> textBlocksOnCanvas = new List<TextBlock>();
IterateOverCanvasAndFindTextBlocksToRTL(canvasToRTL, textBlocksOnCanvas);
foreach (TextBlock textBlockOnCanvas in textBlocksOnCanvas)
ChangeTextBlockToRTL(textBlockOnCanvas, forceRTL);
}
public void RTLTextBlock(TextBlock textBlockToRTL)
{
RTLTextBlock(textBlockToRTL, ForceAllParagraphsAsRTL);
}
public void RTLTextBlock(TextBlock textBlockToRTL, bool forceRTL)
{
ChangeTextBlockToRTL(textBlockToRTL, forceRTL);
}
private void IterateOverCanvasAndFindTextBlocksToRTL(Canvas canvasToIterateOver, List<TextBlock> foundTextBlocks)
{
foreach (Visual curChildToCheckIfTextBlockOrCanvas in canvasToIterateOver.Children)
{
if (curChildToCheckIfTextBlockOrCanvas is TextBlock)
if (!ExcludedTextBlocks.Contains((TextBlock)curChildToCheckIfTextBlockOrCanvas))
foundTextBlocks.Add(curChildToCheckIfTextBlockOrCanvas as TextBlock);
if (curChildToCheckIfTextBlockOrCanvas is Canvas)
if (!ExcludedCanvases.Contains((Canvas)curChildToCheckIfTextBlockOrCanvas))
IterateOverCanvasAndFindTextBlocksToRTL(curChildToCheckIfTextBlockOrCanvas as Canvas, foundTextBlocks);
}
}
private bool HasCanvasesOrTextBlocks
{
get
{
return HasCanvases || HasTextBlocks;
}
}
private bool HasTextBlocks
{
get
{
return TargetTextBlocks.Count != 0;
}
}
private bool HasCanvases
{
get
{
return TargetCanvases.Count != 0;
}
}
private List<Canvas> _TargetCanvases = new List<Canvas>();
[FillXamlElementssByName("TargetCanvasesName")]
internal List<Canvas> TargetCanvases
{
get { return _TargetCanvases; }
set { _TargetCanvases = value; }
}
public string TargetCanvasesName
{
get;
set;
}
private List<TextBlock> _TargetTextBlocks = new List<TextBlock>();
[FillXamlElementssByName("TargetTextBlocksName")]
internal List<TextBlock> TargetTextBlocks
{
get { return _TargetTextBlocks; }
set { _TargetTextBlocks = value; }
}
public string TargetTextBlocksName
{
get;
set;
}
private List<Canvas> _ExcludedCanvases = new List<Canvas>();
[FillXamlElementssByName("ExcludedCanvasesName")]
internal List<Canvas> ExcludedCanvases
{
get { return _ExcludedCanvases; }
set { _ExcludedCanvases = value; }
}
public string ExcludedCanvasesName
{
get;
set;
}
private List<TextBlock> _ExcludedTextBlocks = new List<TextBlock>();
[FillXamlElementssByName("ExcludedTextBlocksName")]
internal List<TextBlock> ExcludedTextBlocks
{
get { return _ExcludedTextBlocks; }
set { _ExcludedTextBlocks = value; }
}
public string ExcludedTextBlocksName
{
get;
set;
}
public bool ForceAllParagraphsAsRTL
{
get;
set;
}
}
}