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);
}
Related
My application detects a foreign object (blob, cluster etc) in the live webcam image and displays object's outline on top of the image. To achieve that I employ Image and Canvas elements as follows:
<Border x:Name="ViewportBorder" Grid.Column="0" Grid.Row="1" BorderThickness="3" Background="AliceBlue" BorderBrush="Red">
<Grid>
<Image x:Name="videoPlayer" Stretch="Uniform" MouseDown="videoPlayer_MouseDown"></Image>
<Canvas x:Name="ObjectsCanvas"></Canvas>
</Grid>
</Border>
Border element in the above XAML is used just to draw a thick red line border around the Grid containing videoPlayer and ObjectsCanvas. Stretch="Uniform" is set to preserve image aspect ratio while being able it to stretch when application window gets maximized.
Every time the new frame arrives from the camera videoPlayer.Source gets updated with frame's bitmap whereas blob detection method yields a list of coordinates used for drawing a Polyline. The Polyline object is then added to ObjectsCanvas to be shown on top of the actual image frame.
Here's a part which draws the blob and adds it to the ObjectsCanvas.Children:
private void DrawBlob(List<Point> corners)
{
this.Dispatcher.Invoke(() =>
{
var myPolyline = new Polyline();
myPolyline.Stroke = System.Windows.Media.Brushes.Yellow;
myPolyline.StrokeThickness = 4;
myPolyline.FillRule = FillRule.EvenOdd;
myPolyline.Points = corners;
Canvas.SetLeft(myPolyline, 0);
Canvas.SetTop(myPolyline, 0);
ObjectsCanvas.Children.Clear(); // remove any old blob polyline
ObjectsCanvas.Children.Add(myPolyline); // add new polyline
});
}
When running the application I observe imperfect overlap of the blob object (thick yellow polyline), it gets somewhat right-shifted as shown in the image below.
Observed imperfection is not due to blob detection algorithm! I verified that by drawing the polylines of very same coordinates using old-fashion GDI methods on the actual bitmap.
It gets worse when I maximize the application window, an action causing videoPlayer to stretch:
I tried setting HorizontalAlignment and VerticalAlignment properties of ObjectsCanvas to Stretch but that does not help. Is there any method to align canvas exactly with the actual displayed image region?
I could get back to drawing the polylines using GDI, but I think it's a shame doing so in WPF...
I think I found a solution.
So, in order to stretch your canvas up to your image size you could wrap your canvas in ViewvBox control and bind your Canvas.Height and Canvas.Width to the image source's Height and Width like so:
<Grid>
<Image x:Name="MyFrame" Stretch="Uniform" />
<Viewbox Stretch="Uniform">
<Canvas
x:Name="MyCanvas"
Width="{Binding ElementName=MyFrame, Path=Source.Width}"
Height="{Binding ElementName=MyFrame, Path=Source.Height}">
<Canvas.Background>
<SolidColorBrush Opacity="0" Color="White" />
</Canvas.Background>
</Canvas>
</Viewbox>
</Grid>
However you need to set your Canvas.Background (you can make it transparent like in the example above), or ViewvBox will hide all of the canvas children otherwise.
Here are some screenshots of it working with a yellow polyline:
One more thing to note here - the coordinates of your polyline should be relative to image resolution.
Hope that helps!
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
I have a circle shaped button and I like to add a pair of Angel Wings to it, but I can't seem to draw it correctly.
I'd like to draw a border with an angel wing on the left and a circle in the middle and an angel wing on the right, in one custom shape..
the Custom shape is the border of the button.
The button is a resizable button, it means it can change Height & Width with the Window, and still maintain the same position.
this button is just an example of what I have made so far.
I've searched for a solution on Google and this site but can't find anything that can help me..
You can use software like Inkscape and with that you can open most image format and from images you can use the trace bitmap option to trace a path. This will create a <path> object in a <canvas>. It can then be used as a background.
things to note :
The quality highly depends on the image source quality and precision. So if your image have lots of color and gradient, huge line thickness and uses anti aliasing you will get very bad result because of a huge amount of vector on the path result. if you use thinner lines and very little color with no gradient you can get amazing conversion result.
You can also hand trace over the image and use that instead of the automatic option. You will get better result like that but it require more work.
With this path created you can create a resource in your application dictionary and use it for icon or background on anything you want. It is scalable in any direction without quality lost as it is now a vector "image".
try looking for image/Photoshop/any other image or drawing method to Xaml converter
you can create an image and convert it to xaml
see http://vectormagic.com
taken form here
Can you try this if it helps
Create Custom control , something like this
<Grid ClipToBounds="True" HorizontalAlignment="Center" VerticalAlignment="Center">
<ed:Arc x:Name="KnobA" ArcThickness="1" ArcThicknessUnit="Percent" EndAngle="360" Height="120" Stretch="None"
Stroke="Black"
StartAngle="0" Width="120" RenderTransformOrigin="0.5,0.5" StrokeThickness="0">
<ed:Arc.Fill>
<ImageBrush ImageSource="/Gazelle;component/Resources/Images/image.png" Stretch="UniformToFill" />
</ed:Arc.Fill>
</ed:Arc>
</Grid>
Use it in your other XAML
<controls:BoundRotaryButton Grid.Column="1" Margin="0,0,35,30"
VerticalAlignment="Bottom" HorizontalAlignment="Right" Opacity="0.2"
Grid.ColumnSpan="2"
BoundRotaryButtonState="{Binding myvm.RotaryPressed, Mode=OneWayToSource,
NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
Create the dependency in code behind of the button control and the handler for mouse clicks.
public static readonly DependencyProperty KnobAPushButtonStateProperty = DependencyProperty.Register("KnobAPushButtonState", typeof (bool), typeof (KnobA));
public bool KnobAPushButtonState
{
get { return (bool) GetValue(KnobAPushButtonStateProperty); }
set { SetValue(KnobAPushButtonStateProperty, value); }
}
private void KnobA_MouseDown(object sender, MouseEventArgs e)
{
Mouse.Capture(this);
KnobAPushButtonState = true;
private void KnobA_MouseUp(object sender, MouseEventArgs e)
{
Mouse.Capture(null);
KnobAPushButtonState = false;
}
In your viewmodel you will know when this dependency property changes the button is pressed or released and invoke the command you need.
I have something like a circular button, which you can rotate and press and so on. But you can use any shape you like with Blend.
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 think I have some difficulty to think through. I have a canvas surrounded by a border and I want to draw a rectangle around the mouse. My problem is, the mouse can move and what I want is like a datagrid. In example, in a datagrid, all cell are already visible, (I know I can make them invisible, that's not the point), but all the cell are static, what I'm trying to do is when I mouseover the canvas, the rectangle be drawned at a static position, sorry if I'm unclear. The picture under should be better.
So as you can see in the first picture my mouse is there and I get some value, what I would like is whenever I'm in the place where I get this value I draw a rectangle over it. As you can see in the second picture when I move my mouse a little bit, I'm still in the area where I have the same value so the rectangle would still be there, and on the third picture I've moved a little further and you see the x coordinate changes and the value also do change then the rectangle would have to be drawned again over the other part
My problem is I don't know how to draw a rectangle of 45 by 40 relative to the mouse but relative to the canvas because if the mouse it's at x : 0 Y : 0 then the rectangle would be 45 by 40 but if my mouse is at X : 10 Y : 10 then the rectangle would have to be, if the mouse is the start point of 10 up the mouse down of 30 and then 10 by left and 35 to the right, I've tried to be as clear as possible, if it's still confuse tell me I will do my best.
You can achieve your requirements easily using the TranslateTransform Class and a couple of double properties:
<Rectangle Name="Rectangle" Stroke="Black" StrokeThickness="1" Fill="{x:Null}">
<Rectangle.RenderTransform>
<TranslateTransform X="{Binding XTransform}" Y="{Binding YTransform}" />
</Rectangle.RenderTransform>
</Rectangle>
You can handle the UIElement.PreviewMouseMove Event on the Canvas element and update your two transform properties from the handler... try something like this:
private void CanvasPreviewMouseMove(object sender, MouseEventArgs e)
{
XTransform = e.GetPosition(Rectangle).X;
YTransform = e.GetPosition(Rectangle).Y;
}
The MouseMove event fires whenever the mouse moves over an element. If I understand your question, you want the know where the mouse is as it moves over the Canvas. So add an event handler to the Canvas. Be sure an name the canvas, you will need the name to refer to is in the mouse event handler.
XAML
<Border Margin='20'
BorderBrush='Orange'
BorderThickness='2'>
<Canvas x:Name='DrawingCanvas'
MouseMove='DrawingCanvas_MouseMove'
Background='Transparent'>
<Rectangle x:Name='MouseRectangle'
Width='30'
Height='30'
Stroke='Purple'
StrokeThickness='2' />
</Canvas>
</Border>
The MouseMove event provides the MouseEventArgs argument. Use it to get the mouse location relative to any element in the UI. In your case, that would be the canvas.
Code
Centers the Rectangle over the mouse tip
private void DrawingCanvas_MouseMove(object sender, MouseEventArgs e) {
Canvas.SetTop(MouseRectangle,
e.GetPosition(DrawingCanvas).Y - MouseRectangle.Height/2);
Canvas.SetLeft(MouseRectangle,
e.GetPosition(DrawingCanvas).X - MouseRectangle.Width /2);
}