I have created an extended splash screen for Windows 10 UWP app using following XAML and C# Code.
XAML Code
<Grid Background="#036E55">
<Canvas>
<Image x:Name="extendedSplashImage" Source="Assets/620.scale-200.png"/>
</Canvas>
<ProgressRing Name="splashProgressRing"
IsActive="True"
Width="20"
Height="20"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Foreground="White"
Margin="20">
</ProgressRing>
</Grid>
C# Code
internal Rect splashImageRect;
private SplashScreen splash;
internal bool dismissed = true;
internal Frame rootFrame;
private double ScaleFactor;
ApplicationDataContainer userSettings = ApplicationData.Current.LocalSettings;
JsonDataHandler dataHandler;
//bool isZipUpdateInProgress = false;
public ExtendedSplashScreen(SplashScreen splashscreen, bool loadState)
{
this.InitializeComponent();
Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);
ScaleFactor = (double)DisplayInformation.GetForCurrentView().ResolutionScale/100;
//System.Diagnostics.Debug.WriteLine("ScaleFactor - " + ScaleFactor + "/n");
splash = splashscreen;
if (splash != null)
{
splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(DismissedEventHandler);
splashImageRect = splash.ImageLocation;
PositionImage();
//PositionRing();
}
rootFrame = new Frame();
}
void PositionImage()
{
extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X);
extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y);
extendedSplashImage.Height = splashImageRect.Height / ScaleFactor;
extendedSplashImage.Width = splashImageRect.Width / ScaleFactor;
}
void PositionRing()
{
splashProgressRing.SetValue(Canvas.LeftProperty, splashImageRect.X + (splashImageRect.Width * 0.5) - (splashProgressRing.Width * 0.5));
splashProgressRing.SetValue(Canvas.TopProperty, (splashImageRect.Y + splashImageRect.Height + splashImageRect.Height * 0.1));
}
void ExtendedSplash_OnResize(Object sender, WindowSizeChangedEventArgs e)
{
// Safely update the extended splash screen image coordinates. This function will be executed when a user resizes the window.
if (splash != null)
{
// Update the coordinates of the splash screen image.
splashImageRect = splash.ImageLocation;
PositionImage();
// If applicable, include a method for positioning a progress control.
PositionRing();
}
}
Now, it works fine if I keep rotation mode on, but when I switch it off, and if I rotate the screen to landscape mode then the logo differs. I am using 620x300 image.
You can try with this code it might help you to get result as you want, First remove all positioning image code and only try with this
<Grid Background="#036E55">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="Assets/620.scale-200.png" Stretch="None"/>
<ProgressRing IsActive="True" Height="30" Width="30" Margin="0,10,0,0" Foreground="White"/>
</StackPanel>
</Grid>
Image and ProgressRing will manage by StackPanel in center of screen and also Image will not differ. Hope it will help you.
Related
I want to increase the height or width(through scrolling) of InkCanvas when the user Ink near the end of the InkCanvas Like OneNote.
Solution Tried:
I tried ScrollViewer for InkCanvas but It didn't work
I thought of re-styling it but I can't find the InkCanvas in generic.xaml
Here is my code for InkCanvas:
<ScrollViewer Grid.Row="1">
<Grid>
<InkCanvas Name="PATH_INK_CANVAS" Canvas.ZIndex="-1"/>
<RichEditBox Name="PATH_RICH_EDIT_BOX" Canvas.ZIndex="0" PlaceholderText="Input Text" Style="{StaticResource RichEditBoxStyle}"/>
</Grid>
</ScrollViewer>
We should find the Bound of Ink in InkCanvas and compare it with ActualSize of the InkCanvas then increase the InkCanvas if we need. It can be done using below code.
public MainPage()
{
this.InitializeComponent();
PATH_INK_CANVAS.InkPresenter.StrokeInput.StrokeEnded += StrokeInput_StrokeEndedAsync;
}
private async void StrokeInput_StrokeEndedAsync(InkStrokeInput sender, PointerEventArgs args)
{
await Task.Delay(100);
var XBound = PATH_INK_CANVAS.InkPresenter.StrokeContainer.BoundingRect.Bottom;
if (XBound > PATH_INK_CANVAS.ActualHeight - 400)
PATH_INK_CANVAS.Height = XBound + 400;
var YBound = PATH_INK_CANVAS.InkPresenter.StrokeContainer.BoundingRect.Right;
if (YBound > PATH_INK_CANVAS.ActualWidth - 400)
PATH_INK_CANVAS.Width = YBound + 400;
}
I've got a simple demo application that uses an image as the background of an InkCanvas and I scale the strokes when the display of the image is resized so that they remain in the same place relative to the image. Since you can draw -> resize -> draw -> resize -> draw this means I have to scale each stroke a different amount each time by assigning the PointTransform on each stroke.
float thisScale = (float)(scale / _prevScale);
foreach (InkStroke stroke in myCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
float thisPointScale = thisScale * stroke.PointTransform.M11;
stroke.PointTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
}
This resizes the length of the strokes perfectly well. However, it does nothing to the thickness of the strokes. This is even more evident when you use a thick or non-uniform pen (eg the highlighter pen).
These link to two screen clips which show the results.
Full-screen - https://1drv.ms/i/s!ArHMZAt1svlBiZZDfrxFqyGU1bJ6MQ
Smaller window - https://1drv.ms/i/s!ArHMZAt1svlBiZZCqHHYaISPfWMMpQ
Any ideas on how I can resize the thickness of the strokes?
Apply a ScaleTransform to the InkCanvas control. That'll take care of scaling the ink stroke,the stroke locations and the background image. Essentially the transform applies to everything contained in the InkCanvas. No need to use the Matrix with the StrokeCollection.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Content="Red Highlighter "
x:Name="InkRedAttributesButton"
Click="InkRedAttributesButton_Click" />
<Button Content="Blue Highlighter "
x:Name="InkBlueAttributesButton"
Click="InkBlueAttributesButton_Click" />
<Button Content="Scale Down"
x:Name="ScaleDownButton"
Click="ScaleDownButton_Click" />
<Button Content="Scale Up"
x:Name="ScaleUpButton"
Click="ScaleUpButton_Click" />
</StackPanel>
<InkCanvas x:Name="myCanvas"
Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top">
<InkCanvas.Background>
<ImageBrush ImageSource="/SO_Questions;component/Images/Star02.jpg"
Stretch="Fill" />
</InkCanvas.Background>
<InkCanvas.RenderTransform>
<ScaleTransform x:Name="InkCanvasScaleTransform" />
</InkCanvas.RenderTransform>
</InkCanvas>
</Grid>
Code
private void ScaleUpButton_Click(object sender, RoutedEventArgs e) {
InkCanvasScaleTransform.ScaleX += .2;
InkCanvasScaleTransform.ScaleY += .2;
}
private void ScaleDownButton_Click(object sender, RoutedEventArgs e) {
InkCanvasScaleTransform.ScaleX -= .2;
InkCanvasScaleTransform.ScaleY -= .2;
}
private void InkRedAttributesButton_Click(object sender, RoutedEventArgs e) {
DrawingAttributes inkAttributes = new DrawingAttributes();
inkAttributes.Height = 12;
inkAttributes.Width = 12;
inkAttributes.Color = Colors.Red;
inkAttributes.IsHighlighter = true;
myCanvas.DefaultDrawingAttributes = inkAttributes;
}
private void InkBlueAttributesButton_Click(object sender, RoutedEventArgs e) {
DrawingAttributes inkAttributes = new DrawingAttributes();
inkAttributes.Height = 12;
inkAttributes.Width = 12;
inkAttributes.Color = Colors.Blue;
inkAttributes.IsHighlighter = true;
myCanvas.DefaultDrawingAttributes = inkAttributes;
}
Screenshots
Scaled 100%
Scaled 60%
Scaling the InkCanvas doesn't always fix the problem especially if you are wanting to save the scaled ink into a gif image file.
Apparently an InkStroke's PointTransform only transforms the location of the stroke's points, but not the size of the PenTip used to draw the stroke. (Not documented anywhere that I can find, but discovered by trial and error. The name 'PointTransform' is a bit of a clue)
So as well as applying your scaling factor to the PointTransform, you also have to scale the PenTip as follows (modification to your original code):
float thisPointScale = thisScale * stroke.PointTransform.M11;
stroke.PointTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
stroke.DrawingAttributes.PenTipTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
Hope this helps someone...
To resize the thickness of the strokes you have to change the Size property of the DrawingAttributes. PenTipTransform doesn't work for pencil - it throws an exception.
The point is that you cannot set the DrawingAttributes property of the stroke directly: https://learn.microsoft.com/en-us/uwp/api/windows.ui.input.inking.inkdrawingattributes
Here is example how to get this:
static IEnumerable<InkStroke> GetScaledStrokes(IEnumerable<InkStroke> source, float scale)
{
var scaleMatrix = Matrix3x2.CreateScale(scale);
var resultStrokes = source.Select(x => x.Clone()).ToArray();
foreach (var inkStroke in resultStrokes)
{
inkStroke.PointTransform = scaleMatrix;
var da = inkStroke.DrawingAttributes;
var daSize = da.Size;
daSize.Width = daSize.Width * scale;
daSize.Height = daSize.Height * scale;
da.Size = daSize;
inkStroke.DrawingAttributes = da;
}
return resultStrokes;
}
Complete example: https://github.com/ycherkes/ScaledInks
I am working on a WPF project, trying to create an analog clock. I have an image of a clock (without the hands) and have set it as a background. I also have images of two hands of clock, which I want to rotate keeping one end fixed (like it happens in a clock). How can I rotate the image keeping its one end fixed in C#.NET (WPF)? What I have tried is the following code:
namespace AnalogWatch
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer dispatcherTimer;
private int degrees = 0;
public MainWindow()
{
InitializeComponent();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
degrees += 5;
if (degrees > 360)
{
degrees = 0;
}
RotateTransform transform = new RotateTransform(degrees,StickImg.Width/2,StickImg.Height/2);
//StickImg.RenderTransformOrigin = new System.Windows.Point(0, 0);
StickImg.RenderTransform = transform;
}
private void Window_ContentRendered_1(object sender, EventArgs e)
{
dispatcherTimer.Start();
}
}
}
It is rotating the image but not keeping its one end fixed. What is the problem here ?
XAML is:
<Window x:Class="AnalogWatch.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" ContentRendered="Window_ContentRendered_1">
<Grid>
<Image x:Name="StickImg" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Margin="207,70,0,0" Source="stick.png"/>
</Grid>
</Window>
Updated.
Your code should work if clock hand exactly in the center of rectangular image.
Like this one
You can do either like you did
RotateTransform transform =new RotateTransform(degrees, StickImg.Width/2,StickImg.Height/2);
or
RotateTransform transform = new RotateTransform(degrees);
StickImg.RenderTransformOrigin = new Point(0.5, 0.5);
Use the RenderTransformOrigin of the element to set the center of rotation.
Note that the coordinates are scaled to 0..1
So to rotate around the center:
RenderTransformOrigin="0.5, 0.5"
Just make sure that the pivot of the hand is in the center of the element.
here's the code i'm using and it works like charm..as qwr suggested clock hand should be exactly in the center of rectangular image
c# code
DispatcherTimer clock = new DispatcherTimer();
public AnalogClock()
{
InitializeComponent();
clock.Interval =TimeSpan.FromMilliseconds(100);
clock.Tick += clock_Tick;
clock.Start();
}
void clock_Tick(object sender, EventArgs e)
{
double milsec = DateTime.Now.Millisecond;
double sec = DateTime.Now.Second;
double min = DateTime.Now.Minute;
double hr = DateTime.Now.Hour;
seconds.LayoutTransform = new RotateTransform(((sec / 60) * 360)+((milsec/1000)*6));
minutes.LayoutTransform = new RotateTransform((min * 360 / 60)+((sec/60)*6));
hours.LayoutTransform = new RotateTransform((hr * 360 / 12)+(min/2));
}
and the XAML code for images
<Grid Margin="-100">
<Image x:Name="clockface" RenderOptions.BitmapScalingMode="HighQuality" Source="images/panel.PNG" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="hours" RenderOptions.BitmapScalingMode="HighQuality" Source="images/hours.PNG" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="minutes" RenderOptions.BitmapScalingMode="HighQuality" Source="images/minutes.PNG" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="seconds" RenderOptions.BitmapScalingMode="HighQuality" Source="images/seconds.PNG" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="194" Margin="100" Width="194"/>
</Grid>
note the i've used the code in a separate usercontrol..
just make sure that the margin between the clock hand image and the grid i'ts contained in should be enough to make room for the image to rotate else it will displace while rotating..
hope this helps..!
I have a textblock control on canvas which can be dragged horizontally to the right correctly as shown in the first and second image.
Then after I a 90 degree rotation angle is applied to its CompositeTransform, dragging the textblock to the right actually move it vertically towards the top as shown by the third and fourth image. What am I missing?
public CompositeTransform CurrentTransform = new CompositeTransform();
.....
TextBlock.RenderTransform = CurrentTransform;
....
private double angle;
public double Angle
{
get
{
return angle;
}
set
{
if (angle != value)
{
angle = value;
CurrentTransform.CenterX = 0;
CurrentTransform.CenterY = 0;
CurrentTransform.Rotation = angle;
}
}
}
The moving of the textbox is handled inside
private void CanvasText_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
CurrentTransform.TranslateX += e.DeltaManipulation.Translation.X;
CurrentTransform.TranslateY += e.DeltaManipulation.Translation.Y;
}
For those who are in the same boat, I managed to fix this by attaching external gesture listener from Windows Phone toolkit instead of using the built-in CanvasText_ManipulationDelta event. The textbox dragging works correctly even after rotation.
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Image x:Name="ImageOriginal"
Source="{Binding WbPreview, Mode=TwoWay}"
Stretch="Uniform"/>
<Grid x:Name="GridDraw"
Tap="GridDraw_Tap"
Background="Transparent"/>
<Canvas x:Name="CanvasText">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap"
DragDelta="GestureListener_DragDelta"/>
</toolkit:GestureService.GestureListener>
</Canvas>
</Grid>
I try to rotate a Border and have the MainWindow change his size based on the new space taken by the Border rotation.
I've set SizeToContent="WidthAndHeight" but window size does't take change when I rotated the border.
Do I need to programmatically set the Width and Height for the MainWindow or this can be achieved changing the xaml code in some other way?
My xaml code:
<Window x:Class="MyClass.MainWindow"
WindowStyle="None" AllowsTransparency='True'
Topmost='False' Background="Transparent" ShowInTaskbar='False'
SizeToContent="WidthAndHeight" WindowStartupLocation="Manual">
<Border Name="MyBorder"
BorderBrush="Transparent"
Background="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Top"
RenderTransformOrigin="0.5,0.5">
</Border>
</Windows>
My c# code on Window_KeyDown:
# RotateTransform rt = new RotateTransform() is declared at class level.
if (e.Key == Key.I)
{
if (rt.Angle + 1 < 360)
{
rt.Angle += 1;
}
else
{
rt.Angle = 0;
}
MyBorder.RenderTransform = rt;
}
Use LayoutTransform instead of RenderTransform
From MSDN: Transforms Overview
LayoutTransform – A transform that is applied before the layout pass. After the transform is applied, the layout system processes the
transformed size and position of the element.
RenderTransform – A transform that modifies the appearance of the element but is applied after the layout pass is complete. By using the
RenderTransform property instead of the LayoutTransform property, you
can obtain performance benefits.
Example
<Border Name="MyBorder"
BorderBrush="Transparent"
Background="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Top"
RenderTransformOrigin="0.5,0.5">
<Border.LayoutTransform>
<RotateTransform Angle="90"/>
</Border.LayoutTransform>
</Border>
So in your case
RotateTransform rt = new RotateTransform(0.0, 0.5, 0.5);
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.I)
{
if (rt.Angle + 1 < 360)
{
rt.Angle += 1;
}
else
{
rt.Angle = 0;
}
MyBorder.LayoutTransform = rt;
}
}}