Zooming into all content of a Canvas - c#

I have this Xaml:
<Grid x:Name="DrawingGrid" Visibility="Collapsed">
<AppBarButton x:Name="ExitDrawingButton" Icon="Cancel" Click="ExitDrawingButton_Click"></AppBarButton>
<ScrollViewer x:Name="DScrollViewer" ManipulationMode="All" MaxZoomFactor="2.0" MinZoomFactor="1.0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" DoubleTapped="DScrollViewer_DoubleTapped" Width="1140" Height="770">
<Canvas x:Name="inkCanvas" Background="Transparent" Width="1140" Height="770">
<StackPanel x:Name="DStackPanel" Orientation="Horizontal" Margin="0,0,0,0">
<Image x:Name="DImage0" HorizontalAlignment="Left" Source="{Binding nextImage}" Width="570" Canvas.ZIndex="0"/>
<Image x:Name="DImage1" HorizontalAlignment="Left" Source="{Binding nextImage}" Width="570" Canvas.ZIndex="0"/>
</StackPanel>
</Canvas>
</ScrollViewer>
</Grid>
I am drawing on Canvas using the CanvasManager.cs class and it is working fine.
Now I need to zoom on the Canvas: Zoom the Canvas (the ink) and Zoom what it contains (the StackPanel + the Images) together.
On doubleTapping the ScrollViewer containing the Canvas I have this method:
private async void DScrollViewer_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
Point point = e.GetPosition(DScrollViewer);
if (DScrollViewer.ZoomFactor == 1)
{
await Task.Delay(300);
DScrollViewer.ChangeView(point.X, point.Y, 2.0F, false);
}
else
{
await Task.Delay(300);
DScrollViewer.ChangeView(point.X, point.Y, 1.0F, false);
}
}
The result is: only the Canvas (its Ink) is Zooming and the StackPanel and its Images are left at the place, same scale, intact!
What Am I doing wrong?

Your mistake is you are assign a constant value for the width of each image (Width="570") so that it will never zoomed in or out unless you have change it's width programmatically.
The best way to change the image's width is bind a variable value for it, you can create a converter that divide the width of canvas over two (canvas.width / 2) and bind the width of each image to this converter..
Then your zoom will work perfectly.

Related

how to check if an element is going out of its parent in c# wpf

I am creating shapes at run time on canvas in my app and except all the shapes, ellipse is going out of canvas. How do I restrict it to canvas? All other shapes are contained in canvas because of the control points at their vertices. How do I keep a check as to not let ellipse go out of canvas without clipping. I have used ClipToBounds and it doesn't meet my needs.
Also, an alternate solution is if I can add a controlpoint at the left side of ellipse of radiusX property. I can't add a controlpoint to left side of radiusX on ellipse. If you could help me with either of that?
radiusXcp = new ControlPoint(this, EllipseGeom, EllipseGeometry.RadiusYProperty, 1, true, false);
radiusXcp.RelativeTo = EllipseGeometry.CenterProperty;
shape_ControlPoints.Add(radiusXcp);
radiusXcp = new ControlPoint(this, EllipseGeom, EllipseGeometry.RadiusXProperty, 0, true, false);
radiusXcp.RelativeTo = EllipseGeometry.CenterProperty;
shape_ControlPoints.Add(radiusXcp);
//EllipseGeom.RadiusX = -EllipseGeom.RadiusX;
//radiusXcp = new ControlPoint(this, EllipseGeom, EllipseGeometry.RadiusXProperty, 0, true, false);
//radiusXcp.RelativeTo = EllipseGeometry.CenterProperty;
//shape_ControlPoints.Add(radiusXcp);
//EllipseGeom.RadiusX = -EllipseGeom.RadiusX;
Here is a quick example of what i would do. It could be improved on and the code is mainly written to be easy to read and follow. It also does not handle the possibility to if the shape's size is bigger than the Canvas (not sure if that is a use case in your project).
For the example I used the "Loaded" event on the Canvas, to reset the position before drawing. You would want this check before you draw the Ellipse object.
private void TestCanvas_Loaded(object sender, RoutedEventArgs e)
{
//canvas = 450 x 800
Ellipse test_ellipse = new Ellipse();
test_ellipse.Width = 100;
test_ellipse.Height = 100;
test_ellipse.Fill = Brushes.Red;
Canvas.SetLeft(test_ellipse, 700);
Canvas.SetTop(test_ellipse, -500);
Reset_Ellipse_Bounds(TestCanvas, ref test_ellipse);
TestCanvas.Children.Add(test_ellipse);
}
private void Reset_Ellipse_Bounds(Canvas myCanvas, ref Ellipse myEllipse)
{
var left = Canvas.GetLeft(myEllipse);
var top = Canvas.GetTop(myEllipse);
//handle too far right
if (left + myEllipse.Width > myCanvas.ActualWidth)
Canvas.SetLeft(myEllipse, myCanvas.ActualWidth - myEllipse.Width);
//handle too far left
if(left < 0)
Canvas.SetLeft(myEllipse, 0);
//handle too far up
if (top < 0)
Canvas.SetTop(myEllipse, 0);
//handle too far down
if (top + myEllipse.Height > myCanvas.ActualHeight)
Canvas.SetTop(myEllipse, myCanvas.ActualHeight - myEllipse.Height);
}
For Completeness the XAML:
<Grid>
<Canvas x:Name="TestCanvas" Loaded="TestCanvas_Loaded" />
</Grid>
The idea is to check the bounding box against the Canvas edges. There are ways to improve this, but i figured the simplest solution is easier to follow.
Within each if statement you could add more logic or a method to do further processing, but this should answer the general question of knowing if it is outside the parent.
Just set ClipToBounds="true" to its father control, it avoids the canvas to be drawn outside of it.
In my case I set it to Grid as followed :
<Grid x:Name="MainGrid" Background="WhiteSmoke" ClipToBounds="true">
<Canvas Margin="10" Background="Transparent"
SizeChanged="ViewportSizeChanged"
MouseLeftButtonDown="ViewportMouseLeftButtonDown"
MouseLeftButtonUp="ViewportMouseLeftButtonUp"
MouseMove="ViewportMouseMove"
MouseWheel="ViewportMouseWheel">
<Canvas x:Name="canvas" Width="1000" Height="600"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas.RenderTransform>
<MatrixTransform x:Name="transform"/>
</Canvas.RenderTransform>
</Canvas>
<Canvas x:Name="canvas2" Width="1000" Height="600"
HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas.RenderTransform>
<MatrixTransform x:Name="transform2"/>
</Canvas.RenderTransform>
</Canvas>
</Canvas>
</Grid>

Uwp more deep shadow effect for text or textblock

I am trying to make more deep black shadow effect to make readable text , infront white background .
I am using this code
c# void method of loaded
var compositor = ElementCompositionPreview.GetElementVisual(this.grid).Compositor;
var brush = compositor.CreateColorBrush(Colors.Black);
var spriteVisual = compositor.CreateSpriteVisual();
spriteVisual.Size = this.grid.RenderSize.ToVector2();
var dropshadow = compositor.CreateDropShadow();
dropshadow.Mask = txtBlock.GetAlphaMask();
dropshadow.Color = brush.Color;
dropshadow.BlurRadius = 9.5f;
dropshadow.Opacity = 1.9f;
spriteVisual.Shadow = dropshadow;
ElementCompositionPreview.SetElementChildVisual(this.grid, spriteVisual);
xaml
<Grid Background="White">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid Loaded="grid_Loaded"
x:Name="grid" />
<TextBlock IsTextSelectionEnabled="True"
x:Name="txtBlock"
Text="Drop Shadow"
Foreground="White" Style="{StaticResource BodyTextBlockStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Center" ></TextBlock>
</Grid>
</Grid>
Result
[![Result image][1]][1]
My Problem it is not enough black color shadow effect or opacity to watch the text .
Result
http://i.imgur.com/d6FglQT.png
I am trying to make that black effect more deep,
My Target to make shadow effect like this
Target
http://i.imgur.com/bOiRnCS.png

How to get Zoom value in scroll viewer in C# wpf Kinect SDK 2.0?

I have recently started using the Kinect SDK 2.0 and am focusing on a zoom and pan functionality, as in the Control Basics-WPF sample.
I have got the zoom and pan functionality up and running. The problem is that I wish to access the value of the amount of zoom which has been performed by the Pinch zoom gesture.
Here is my xaml:
<UserControl x:Class="ImageNav.NavigationImage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:k="http://schemas.microsoft.com/kinect/2014"
mc:Ignorable="d"
d:DesignWidth="1200"
d:DesignHeight="700"
>
<Grid Grid.RowSpan="2">
<ScrollViewer Name="scrollViewer" Grid.Row="0"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
k:KinectRegion.IsHorizontalRailEnabled="true" k:KinectRegion.IsVerticalRailEnabled="true"
k:KinectRegion.ZoomMode="Enabled">
<Image Name="navigationImage" RenderTransformOrigin="0.5, 0.5" />
</ScrollViewer>
<TextBox x:Name="ZoomTextBox" Grid.Row="1" TextWrapping="Wrap" Text="Zoom: 100%" IsEnabled="False" Panel.ZIndex="10" BorderThickness="0" HorizontalAlignment="Right" VerticalAlignment="Bottom" FontSize="20"/>
</Grid>
</UserControl>
I would have wanted there to be something like k:KinectRegion.ZoomFactor, but that isnt available. I've also tried to see what changes in the UI elements when I perform the zoom gesture, by writing the Height and ActualHeight properties of the ScrollViewer scrollViewer and Image navigationImage to a log file, but they show no change whatsoever.
When I perform the zoom gesture, I would like to get the value of zoom i.e. the current height and width of the image with respect to the original height and width.
This has nothing to do with Kinect SDK, this is more of a ScrollViewer zooming issue. There is no k:KinectRegion.ZoomFactor because zooming doesn't change the actual size of the image, it only performs some layout transformations, therefore you can get the zooming factor from LayoutTransform property of your Image.
Something like the following code should get the zooming factor:
UserControl.Code:
public NavigationImage()
{
InitializeComponent();
DataContext = this;
_zoom = 1.0;
}
double _zoom;
public string ZoomPercentage
{
get
{
return _zoom * 100 + "%";
}
}
private void scrollViewer_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
_zoom += 0.1;
}
else
{
_zoom -= 0.1;
}
ScaleTransform scale = new ScaleTransform(_zoom, _zoom);
navigationImage.LayoutTransform = scale;
OnPropertyChanged("ZoomPercentage");
e.Handled = true;
}
UserControl.Xaml:
<UserControl x:Class="ImageNav.NavigationImage" ... >
<Grid Grid.RowSpan="2">
<ScrollViewer Name="scrollViewer" Grid.Row="0" PreviewMouseWheel="scrollViewer_MouseWheel"
....
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
k:KinectRegion.IsHorizontalRailEnabled="true" k:KinectRegion.IsVerticalRailEnabled="true"
k:KinectRegion.ZoomMode="Enabled"
>
<Image Name="navigationImage" RenderTransformOrigin="0.5, 0.5"/>
</ScrollViewer>
<TextBox x:Name="ZoomTextBox" Grid.Row="1" Text="{Binding ZoomPercentage, Mode=OneWay}" .... />
</Grid>
</UserControl>

How to place an image by its center, not top-left corner?

I have an image (inside canvas). I need to specify the coordinates of the image in text box, and I want the image center to be in this point (not its top-left corner). How can I do that?
Update: I don't need to place my image in the center of the canvas. I want the position of the image to be defined by image center. Example, I have a code: <Image source"..." canvas.Left="0" canvas.Top="0">, and this point (0,0) means that the image center is in the top-left corner of the canvas.
Set the position using Attached properties:
Canvas.Left
Canvas.Top
If you want to place at center, set
Canvas.SetLeft(image, (canva.Width - Image.Width) / 2);
Canvas.SetTop(image, (canva.Height- Image.Height) / 2);
Also look Align images in WPF canvas in center
Update
Canvas.SetLeft(image, Image.Width / 2);
Canvas.SetTop(image, Image.Height / 2);
You can set it from behaviors for example
<Window x:Class="WpfSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:wpfSample="clr-namespace:WpfSample"
Title="MainWindow"
Width="800"
Height="800"
Background="Gray">
<Border Width="400"
Height="400"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Black"
BorderThickness="2">
<Canvas >
<Rectangle Fill="OrangeRed" Width="150" Height="150">
<i:Interaction.Behaviors>
<wpfSample:CenterBehavior/>
</i:Interaction.Behaviors>
</Rectangle>
</Canvas>
</Border>
</Window>
and the behavior (raw sample)
public class CenterBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
base.OnAttached();
UpdatePosition();
AssociatedObject.SizeChanged += OnSizeChanged;
}
private void UpdatePosition()
{
Canvas.SetLeft(AssociatedObject, -AssociatedObject.Width/2);
Canvas.SetTop(AssociatedObject, -AssociatedObject.Height/2);
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdatePosition();
}
}
Just subtract half of your Image.Width value your current Canvas.Left value and subtract half of your Image.Height value your current Canvas.Top value.

Rectangle visible only in certain grid area

How to make the green rectangle to be visible only inside the blue one? The blue is a border of a grid. I want to cut off everything that is not inside this grid. Notice that the green rectangle will be moving.
As there is no ClipToBounds property in Silverlight, you would have to set the Clip property to a RectangleGeometry.
When the Grid's size is fixed, you may simply set a fixed size rectangle:
<Grid>
<Grid.Clip>
<RectangleGeometry Rect="0,0,400,600"/>
</Grid.Clip>
...
</Grid>
When the Grid's size can change, you may set the Clip property in a SizeChanged handler:
<Grid SizeChanged="GridSizeChanged">
...
</Grid>
The handler code:
private void GridSizeChanged(object sender, SizeChangedEventArgs e)
{
((UIElement)sender).Clip =
new RectangleGeometry
{
Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height)
};
}
<Grid Width="200" Height="100">
<Grid.Clip>
<RectangleGeometry Rect="0, 0, 200, 100"/>
</Grid.Clip>
source: http://www.scottlogic.co.uk/blog/colin/2009/05/silverlight-cliptobounds-can-i-clip-it-yes-you-can/

Categories