Clip UWP TextBlock as it moves out of its container - c#

I'm attempting to build an odometer like effect in UWP where when a number is incremented it slides up and dissappears while the incremented number appears by sliding up from the bottom (in a very similar mannor to how the Odometer JS library works).
I have the number contained in a text block, that is animating properly.
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="Digit1">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-80" />
</DoubleAnimationUsingKeyFrames>
Currently, when the number moves up it is still completely visible. I want the TextBlock to be "clipped" to its containing Canvas so that it progressively dissappears as it moves outside the bounds of the Canvas.
I have tried both clipping the TextBlock to the Canvas and visa versa, neither of which had the desired effect.
<Canvas x:Name="Odometer"
Clip="{Binding Clip, ElementName=Digit1}">
<TextBlock x:Name="Digit1"
FontSize="100"
Text="8"
Canvas.Left="-104"
Canvas.Top="-30"
RenderTransformOrigin="0.5,0.5"
Clip="{Binding Clip, ElementName=Odometer}">
<TextBlock.RenderTransform> <CompositeTransform /> </TextBlock.RenderTransform>
</TextBlock>
</Canvas>
I do not need to use a Canvas, it's just what I was playing around with. I'm still very new to UWP, so any help would be appreciated.

If you refer to UIElement.Clip:
The clipping geometry for UIElement.Clip in the Windows Runtime API must be a RectangleGeometry.
So, if you want to give a outline for canvas, you need to specify a RectangleGeometry for your canvas.clip, which take a rect of your canvas's actual size.
You can achieve this progrmmatically:
private void Odometer_Loaded(object sender, RoutedEventArgs e)
{
RectangleGeometry rectangle = new RectangleGeometry();
rectangle.Rect = new Rect(0, 0, Odometer.ActualWidth, Odometer.ActualHeight);
Odometer.Clip = rectangle;
}
And don't forget to remove the clip in xaml:
<Canvas x:Name="Odometer" Loaded="Odometer_Loaded">
<TextBlock x:Name="Digit1"
FontSize="100"
Text="8"
Canvas.Left="104"
Canvas.Top="10"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<CompositeTransform />
</TextBlock.RenderTransform>
</TextBlock>
</Canvas>

Related

Is is possible to change cursor blink rate and cursor movement speed in wpf?

I tested both Word 2010 and Word 2019 on the same systems and same Keyboard Properties.
I did not change the properties of the Windows Keyboard.
Cursor movement and cursor blinking were fast in Word 2010, but very slow in Word 2019.
I want to modify Cursor's blink rate and movement speed in wpf project.
How to do it? Thanks for any help.
<Grid>
<TextBox x:Name="tb" Height="230" Padding="4" TextWrapping="Wrap" AcceptsReturn="True" Width="320" Focusable="True" Loaded="tb_Loaded" />
</Grid>
private void tb_Loaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus(tb);
}
Edit:
I looked here but don't know if it is correct and how to do it.
WPF basically respects Windows's control panel settings of the blink rate. So does Word 2019 on my system. If you want to change the rate on your textbox, your only option is to disable the built-in caret (text cursor), and draw it yourself.
The following is shamelessly stolen inspired by this article, with some kinks ironed out:
SelectionChanged triggers too early when TextBox height is not a full multiple of line height causing buggy cursor positioning. Changed to LayoutUpdated.
Caret.Height respects the text height, instead of hardcoded.
Now on to the magic. Try this on your MainWindow.xaml:
<Grid x:Name="YouNeedAGridToContainTheTextBoxAndCanvas">
<TextBox x:Name="CustomTextBox"
FontSize="20"
AcceptsReturn="True" TextWrapping="Wrap"
CaretBrush="Transparent" />
<!--CaretBrush must be Transparent, as we will draw manually below-->
<Canvas ClipToBounds="True">
<Border x:Name="Caret"
Width="4"
Visibility="Collapsed"
Background="Transparent"> <!--Start drawing Transparent-->
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="Background.Color"
FillBehavior="HoldEnd">
<ColorAnimationUsingKeyFrames.KeyFrames>
<!--Ease to Red in 1sec-->
<EasingColorKeyFrame KeyTime="0:0:1.0" Value="Red"/>
<!--Ease back into Transparent in another 1sec-->
<EasingColorKeyFrame KeyTime="0:0:2.0" Value="Transparent" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
</Canvas>
</Grid>
You then need to manually update the drawing position by using code behind in your MainWindow.xaml.cs:
public MainWindow() //Constructor
{
InitializeComponent();
CustomTextBox.LayoutUpdated += (_, _) => {
var rect = CustomTextBox.GetRectFromCharacterIndex(CustomTextBox.CaretIndex);
if (rect.IsEmpty) return;
Canvas.SetLeft(Caret, rect.Left);
Canvas.SetTop(Caret, rect.Top);
Caret.Height = rect.Height;
};
CustomTextBox.LostFocus += (_, _) => Caret.Visibility = Visibility.Collapsed;
CustomTextBox.GotFocus += (_, _) => Caret.Visibility = Visibility.Visible;
CustomTextBox.Focus();
}
Feel free to tweak the color animation, adding frames as needed and playing with the KeyTime for faster/slower pulsing. Use <DiscreteColorKeyFrame> instead of <EasingColorKeyFrame> if you want a hard blink instead of pulsing.

windows phone Image Translation (movement/animation)

Im trying to animate a image that moves from the right side of the screen to the left, i guess thats what translate is for, but not really sure how it works, or whats the best solution. So far i have this:
<Image Height="50" Width="50" Source="/Assets/Img/cloud.png" Stretch="Uniform">
<Image.RenderTransform>
<TranslateTransform x:Name="p1Translate" X="0" Y="0"/>
</Image.RenderTransform>
</Image>
Which is nothing!
So can someone help me, translate the cloud.png just in the X axis?
Greets,
José Correia
Did you try using the CompositeTransform for your image? You could use Blend to come up with a storyboard animation.
XAML storyboard animation moving images from outside viewport-windows phone 8
For further reference:
Images Animation By Using Story Board in Windows Phone 8/8.1
I believe this article should answer all your questions: Quickstart: Animations for Windows Phone
While you can use the RenderTransform in order to position objects relative to where the layouting engine puts them the easier way is to place the Control you want to move around inside a Canvas which directly attaches position properties to that Control. This is shown in one of the samples in the article I linked to.
Thanks for all the help, heres how i did it:
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="image">
<EasingDoubleKeyFrame KeyTime="0" Value="-90"/>
<EasingDoubleKeyFrame KeyTime="0:0:8" Value="-598.826"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
<Image x:Name="image" Source="/Assets/Img/bg_cloud.png" Stretch="Fill" RenderTransformOrigin="50,50" Width="70" Height="40" Margin="497,596,-87,164">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
And Blend really helped me out!
Best regards,
José Correia

Update page layout before Thread.Sleep()

I have a TextBlock on my page with Text value null (""). When I click a button I want to change the Text value for this TextBlock, pause half a second and then move the TextBlock one pixel at a time to a certain point.
I tried using Thread.Sleep(), but so far, I have a problem. I click the button, the UI thread pauses for half a second, then the TextBlock suddenly appears and starts moving. I want it to appear as soon as I click the button.
P.S.: I know Thread.Sleep() doesn't work. I am willing to use anything that works.
Storyboards and animations are the preferred mechanism for moving items on the screen. For one thing, they are optimized to work with the phones threading model. For another, putting your UI thread to sleep is a bad idea as you are making a non responsive application.
Here's a quick example of how to move a texblock with a story board.
The UI elements.
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<TextBlock
Margin='79,263,177,307'
Name='textBlock1'
Text='TextBlock'
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<CompositeTransform />
</TextBlock.RenderTransform>
</TextBlock>
<Button
Content="Button"
Height="80"
Margin="116,0,188,144"
VerticalAlignment="Bottom"
Click='Button_Click' />
</Grid>
The storyboard, defined in the page resources section.
<phone:PhoneApplicationPage.Resources>
<Storyboard
x:Name="MoveTextBlockStoryboard">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="textBlock1">
<EasingDoubleKeyFrame
KeyTime="0"
Value="0" />
<EasingDoubleKeyFrame
KeyTime="0:0:1.1"
Value="120" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="textBlock1">
<EasingDoubleKeyFrame
KeyTime="0"
Value="0" />
<EasingDoubleKeyFrame
KeyTime="0:0:1.1"
Value="-105" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
The code that changes the text and starts the storyboard.
private void Button_Click(object sender, RoutedEventArgs e) {
textBlock1.Text = "new text";
MoveTextBlockStoryboard.Begin();
}
Try using a storyboard instead of writing code to do this. I think it will perform better for you than a manual approach.

WPF Image Transformation

I have simple graphic images which I would like to transform on triggered events. Transform means change the width or move it to another position.
For now I use the Image element of the toolbox and Animations via Storyboard, for instance DoubleAnimation or ThicknessAnimation.
However the following issues arise:
the images flickers when changing the width
the image quality varies, does WPF support vector graphics?
Regarding 1. my question is, if other animations should be used.
So I tried the Transformation, see the code :
<Image Height="150" HorizontalAlignment="Left" Margin="12,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Source="images/side_view.jpg" Width="1244">
<Image.RenderTransform>
<ScaleTransform x:Name="Minimize" ScaleX="1.0" ScaleY="1.0"/>
</Image.RenderTransform>
</Image>
<Button Content="Next Train" Height="23" HorizontalAlignment="Left" Margin="528,233,0,0" Name="btnNext" VerticalAlignment="Top" Width="75" />
<Grid.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="btnNext">
<BeginStoryboard>
<Storyboard TargetName="Minimize" TargetProperty="ScaleX">
<DoubleAnimation To="0.65" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
Works the same as the Animation I applied to width and margin. However, it still flickers! Are there any reasonable explanations?
If you're animating the Width of an image, you're making WPF re render the image, and create it from scatch each time. It goes through both the Layout process and the Rendering process, which makes it flicker and not work as best as it could be.
The best option here is to animate a ScaleTransform. ScaleTransform is done completely in hardware via DirectX and therefor will be extremlely fast, it won't flicker, and the image quality should stay pretty much the same the whole way. (unless ofcourse you are resizing it substantially in which case you'll lose percision.)

WPF: How to put an object/shape at the end of a line path/stroke?

I just wanna ask if there's a way where I could put an object (circle) at the end of a particular line path.
Similar to this:
--------------------------------------------O
Start End
Right now, I have the following code for tracing the line:
<Grid x:Name="LayoutRoot" >
<Path Stroke="Red" StrokeThickness="4" x:Name="path4" Data="{Binding MyProperty1}" >
<Path.StrokeDashArray>
<System:Double>500</System:Double>
<System:Double>1000</System:Double>
</Path.StrokeDashArray>
</Path>
</Grid>
where the data of my path (e.g. M532,668 L523,695 361,663 101,678 117,638) varies.
my animation looks like this...
<Storyboard x:Key="Story1" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="path1"
Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="500"/>
<SplineDoubleKeyFrame KeyTime="00:00:08" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Any suggestions?
There are at least a couple of ways you could do this; which is best probably depends on the relationship of the circle to the line.
If the circle is conceptually part of the same shape as the line, change your Path to include an ellipse (arc) at the end of the line. This could be done by changing the path Data, either by adding a circle to the end or by adding another Figure to the PathGeometry.
If the circle is conceptually a separate component, and you just want to place that component next to the line, you can just use a StackPanel with its Orientation set to Horizontal:
<StackPanel Orientation="Horizontal">
<Path /> <!-- The line -->
<Ellipse /> <!-- The circle -->
</StackPanel>
(Note: in some scenarios, you can do this using the EndLineCap property. That won't work in this case though because it looks like you want the circle to be bigger than the stroke thickness. Line caps are always the same thickness as the line.)

Categories