Im trying to build a high performance app on UNO platform (WPF/Windows/Wasm) that allows the user to draw primitive shapes (lines, rectanges, etc) Since it will have snapping to points, and showing snap point it should be smooth.
The mouse lags when moving over the canvas, the lag is small, but users of this app will be working very quickly and these lags make it feel unresponsive. Is there any way to speed this up?
A simple white box demo
MainPage.Xaml
<Grid>
<Canvas Width="2088" Height="2100.17014099374" x:Name="MainCanvas" >
<Canvas.Background>
<SolidColorBrush Color="#eaeaea"></SolidColorBrush>
</Canvas.Background>
<Ellipse Name="SnapPoint" Canvas.Top="400" Canvas.Left="400" Width="25" Height="25" Fill="Blue"></Ellipse>
</Canvas>
</Grid>
MainPage.Xaml.cs
private void MainCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
var position = e.GetCurrentPoint(MainCanvas).Position;
Canvas.SetLeft(SnapPoint, position.X);
Canvas.SetTop(SnapPoint, position.Y);
}
I have also tried binding the Left and Top properties of the ellipse to view model, but the delay is the same.
I was using remote desktop from Mac to Windows, this caused a delay in the mouse pointer on the screen
Related
I have a ScrollViewer with Image in it. I attached listener to MouseWheel event so I could zoom in/out the image. The code looks like this:
private void ImageMouseWheel(object sender, MouseWheelEventArgs e)
{
Matrix matrix = image.LayoutTransform.Value;
if (e.Delta > 0)
matrix.ScaleAt(1.5, 1.5, e.GetPosition(image).X, e.GetPosition(image).Y);
else
matrix.ScaleAt(1.0 / 1.5, 1.0 / 1.5, e.GetPosition(image).X, e.GetPosition(image).Y);
image.LayoutTransform = new MatrixTransform(matrix);
}
It pretty much works, but it has odd quirk -- when the image is so zoomed out that is at state "fit to parent" visually I cannot it zoom out more (visually), but the matrix is scaled still.
This is bad in sense that any computation after this point is wrong, and also it has strange effect in UI, say user starts from "fit to parent" zoom:
zoom out --> visually no change, internally matrix is zoomed out
zoom in --> surprise, visually no change, internally matrix is zoomed in
zoom in --> visually zoom in, matrix is also changed (OK)
Because of those problems I would like either to continue zooming out visually in order to keep both things (internal and visual) in sync.
How to achieve this?
Xaml:
<DockPanel>
<ScrollViewer Name="imageScrollViewer" Grid.Column="1" MouseWheel="ImageMouseWheel"
CanContentScroll="true" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<Image MouseWheel="ImageMouseWheel" Name="image" Source="{Binding Path=Bitmap}"
MouseMove="Image_MouseMove"></Image>
</ScrollViewer>
</DockPanel>
Update: Originally I asked how to continue scaling visually or stop internally, but I found out that the last step of zooming out, when the image hits the state "fit to parent" is already out of sync internally-visually. For example position of the mouse is not correctly decoded above such image when moving the mouse around. Only when I zoom in a little the positions are correct. So the only way I see is to scale it visually correctly.
Hmm, I am tempted to delete this embarrassing question, but on the other hand maybe someone will have the same problem in future.
The problem is image is zoomed out, but later the dock panel zoom it in back. The image does not know about it so the math goes astray. The solution is to add some container which does not do additional scaling on itself, like stack panel.
Thus the solution lies in xaml:
<DockPanel>
<StackPanel>
...
</StackPanel>
</DockPanel>
Hello, I have been trying to work this problem out for some time now,
I hope that you are able to lead me in the right direction!
The goal is to have a "flashlight" effect in my wpf game, to do this I have pursued 2 main options.
Have a black png image that is 200% width & height of window with a hole in the center, then move the image with the mouse
Have a black image the size of the window, and have an opacity mask element that is a circle shape that looks through the black layer to the content below. This circle moves with the mouse.
I cannot get either of these options to work, in wpf when you have an opacity mask it appears you cannot move the element that is "punching through" the layer. And for the large image method, I cannot convert a mouse Point object to an image's position. Below are some potential methods of getting mouse position, I have not been able to move the image to "point" location.
Point to screen
private void MouseCordinateMethod(object sender, MouseEventArgs e)
{
var relativePosition = e.GetPosition(this);
var point= PointToScreen(relativePosition);
_x.HorizontalOffset = point.X;
_x.VerticalOffset = point.Y;
}
GetPosition
var point = e.GetPosition(this.YourControl);
The final game will be using kinect for controls, so if there is a way to do this with kinect libraries or natively that is also an option. Thank you.
You could use a Path element with a CombinedGeometry consisting of a very large RectangleGeometry and an excluded (and therefore transparent) EllipseGeometry, which is moved by changing its Center property on mouse input:
<Grid MouseMove="Grid_MouseMove">
<TextBlock Text="Hello, World" FontSize="40"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Path Fill="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,10000,10000"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry x:Name="circle" RadiusX="100" RadiusY="100"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Grid>
The MouseMove handler:
private void Grid_MouseMove(object sender, MouseEventArgs e)
{
circle.Center = e.GetPosition((IInputElement)sender);
}
once again hi everybody., recently i have created face changer application for windows phone 8 devices where i have designed a page with two image control where
1 st image as background and 2 nd image control is foreground.
i have added " GestureListener " to my 1 st image control (background) where i have to "Pinch , Zoom in, zoom out , drag" that background image using "toolkit:GestureService.GestureListener ".
i did everything fine like i can able to pinch , zoom, drag an image successfully... But,
the problem is " I Can't able to Pinch or drag the image from anywhere i touch my finger(s) on the screen"., so that the pinch zoom or drag is much difficult for me to zoom in/out or drag an image .,
But in I-Phone/i-pad/i-pod & all Android devices i can able to pinch to zoom in/out or drag an image from touching anywhere on the screen.,
like already i said my 1 st image is background which can be added gesture control and 2 nd image is normal image control which cant zoom or drag.,
Here is my code.,
my XAML Code :
<Grid x:Name="ContentPanel" Grid.RowSpan="2">
<Canvas x:Name="screenArea" Width="400" Height="580" >
<Image x:Name="myImage" Width="400" Height="580" RenderTransformOrigin="0.5, 0.5" CacheMode="BitmapCache" >
<Image.RenderTransform>
<TransformGroup>
<CompositeTransform x:Name="MyMustacheTransformation" />
</TransformGroup>
</Image.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener PinchStarted="OnPinchStarted"
PinchDelta="OnPinchDelta"
DragDelta="OnDragDelta"/>
</toolkit:GestureService.GestureListener>
</Image>
<Image x:Name="frameImage" Width="400" Height="580" Stretch="Fill"/>
</Canvas>
</Grid>
And my CS code for pinch_start, Drag_delta, pinch_delta are
private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
{
_initialAngle = MyMustacheTransformation.Rotation;
_initialScale = MyMustacheTransformation.ScaleX;
}
private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
MyMustacheTransformation.Rotation = _initialAngle + e.TotalAngleDelta;
MyMustacheTransformation.ScaleX = _initialScale * e.DistanceRatio;
MyMustacheTransformation.ScaleY = _initialScale * e.DistanceRatio;
}
private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
{
Image rect = sender as Image;
TranslateTransform transform = rect.RenderTransform as TranslateTransform;
MyMustacheTransformation.TranslateX += e.HorizontalChange;
MyMustacheTransformation.TranslateY += e.VerticalChange;
}
I Hope you can understand what am asking and sorry if my words are not clear.,
if you ll already used face changer applications on either Android/i-phone/pod/pad devices means they can understand easily what am expecting.,
MY Goal Is :
" i can able to Pinch to Zoom in/out , drag an image from touching anywhere on the layout.. like in i-phone/pod/pad & android devices"
I have struggle with couple of weeks., please give some solutions.,
i you give any sample code means that could more useful for me.,
Thanks in advance guys.,
The problem is that you attached the GestureListener to the image, hence you only get gestures when you touch the image.
Attach the listener to the outermost Grid.
I'm running into a problem of "jitters" when moving the X, Y coordinates of controls. Basically, I got an animation to work two different ways: 1) TranslateTransform of the X property, and 2) A Timer that calls Canvas.SetLeft. Both of which cause the image to move, but not smoothly.
XAML:
<Canvas Margin="0" Name="CanvasContainer">
<Canvas Margin="0" Name="FirstCanvas" Background="White">
<Image Name="FirstImage" Opacity="1" Margin="0,0,0,0" Canvas.Left="0" Canvas.Top="0" Source="someImage.png" />
</Canvas>
<Canvas Margin="0" Name="SecondCanvas" Background="DarkOrange">
<Image Name="SecondImage" Opacity="1" Margin="0,0,0,0" Canvas.Left="0" Canvas.Top="0" Source="anotherImage.png" />
</Canvas>
</Canvas>
TranslateTransform:
private void StartMovement(double startX, double endX, double milliseconds = 1000)
{
GuiDispatcher.Invoke(DispatcherPriority.Normal, new Action<Canvas, double, double, double>(MoveTo), Canvas, startX, endX, milliseconds);
}
private void MoveTo(Canvas canvas, double startX, double endX, double milliseconds)
{
canvas.RenderTransform = new TranslateTransform();
var animation = new DoubleAnimation(startX, endX, TimeSpan.FromMilliseconds(milliseconds));
canvas.RenderTransform.BeginAnimation(TranslateTransform.XProperty, animation);
}
Is there a better method for accomplishing this, or do I have something set up wrong? Any help would be appreciated.
Either of those methods are generally fine for animations in WPF. If the image isn't moving smoothly, I have a few of questions.
How big is the image?
Large images take longer to render, and will therefore not animate as well.
Are you rendering the image at its native resolution?
Like large images, scaling can slow down the render, as it takes longer to calculate the rendered pixels.
How good is your graphics card? And are your drivers up to date?
WPF uses your graphics card to render, unless it isn't good enough. If it has to fallback to software rendering, everything gets sluggish.
How far is the image moving?
The further the image moves, the fewer frames will be drawn per second, which could leave to the appearance of the animation being jerky.
If it is a framerate issue because the image is moving too far too quickly, you can increase the desired framerate by setting the Timeline.DesiredFrameRate property:
Timeline.SetDesiredFrameRate(animation, 120);;
In WPF, the default target framerate is 60, and is by no means guaranteed. But one of the primary uses for this attached property is to decrease horizontal tearing, so it might help.
I'm trying to integrate a screenshot grabbing feature in my WPF app and I'd like it to look like snipping tool.
So far I've managed accomplish something similar by creating a fullscreen window (with a canvas) with opacity set to 0.5 and dark background. When I click somewhere and start dragging, a white rectangle is drawn, generating an effect similar to this.
What I'd like to have is the inner part of that rectangle opening a opacity hole in the background canvas, so that I could see through the selected area - just like snipping tool.
Problem is, being fairly new to .NET, I have no idea how or where to start. Did some research and tests on the OpacityMask field of the screenshot window but got nowhere.
Here's a little vid to show the current effect.
Edit: Also, as bonus question, is there an easy way to grab a screenshot that spans across multiple monitors (virtual screen)? Graphics.CopyFromScreen() only seems to work for 1 screen.
Already fixed this and seems to work for all possible weird virtual desktop layouts:
// Capture screenie (rectangle is the area previously selected
double left = Canvas.GetLeft(this.rectangle);
double top = Canvas.GetTop(this.rectangle);
// Calculate left/top offset regarding to primary screen (where the app runs)
var virtualDisplay = System.Windows.Forms.SystemInformation.VirtualScreen;
var primaryScreen = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
if (virtualDisplay.Left < primaryScreen.Left)
{
left -= Math.Abs(virtualDisplay.Left - primaryScreen.Left);
}
if (virtualDisplay.Top < primaryScreen.Top)
{
top -= Math.Abs(virtualDisplay.Top - primaryScreen.Top);
}
You can have a CombinedGeometry with GeometryCombineMode="Exclude" creating a "punched" effect. Sample:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" AllowsTransparency="True"
WindowStyle="None" Background="Transparent">
<Canvas >
<Path Stroke="Black" Fill="White" Opacity=".5">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,800,600" >
</RectangleGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<RectangleGeometry Rect="50,50,100,100" >
</RectangleGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Canvas>
</Window>