Custom Edge Swipe Event in Windows (For Bottom Edge) - c#

I want to open an app or do something with a bottom swipe, so what can I do to get the event? It's like this: https://www.microsoft.com/zh-cn/videoplayer/embed/fc016fcc-2bb1-4294-b236-343e1a533401?autoCaptions=en-us
I tried using the EdgeGesture class in UWP apps, which provides events for Starting, Completed, and Canceled. But when I swiped at the edge of the screen, no event was triggered.
In MainPage.xaml.cs:
public MainPage()
{
this.InitializeComponent();
//ApplicationView.GetForCurrentView().TryEnterFullScreenMode();
EdgeGesture gesture = EdgeGesture.GetForCurrentView();
gesture.Starting += Gesture_Starting;
gesture.Completed += Gesture_Completed;
gesture.Canceled += Gesture_Canceled;
}
private void Gesture_Canceled(EdgeGesture sender, EdgeGestureEventArgs args)
{
throw new NotImplementedException();
}
private void Gesture_Completed(EdgeGesture sender, EdgeGestureEventArgs args)
{
throw new NotImplementedException();
}
private void Gesture_Starting(EdgeGesture sender, EdgeGestureEventArgs args)
{
throw new NotImplementedException();
}
Don't know if I did something wrong, can help me? Or is there another way to do this?

In desktop mode, the UWP application is a window application that makes it difficult to capture screen edge slip events, and EdgeGesture may work in tablet mode.
In order to adapt to the sliding needs of different situations, you can consider using GestureRecognizer.
Here I will give you a simple page for reference.
<Page ...>
<Grid Background="White">
</Grid>
</Page>
private GestureRecognizer _GestureRecognizer;
PointerEventHandler PointerPressedEventHandler;
PointerEventHandler PointerMovedEventHandler;
PointerEventHandler PointerReleasedEventHandler;
PointerEventHandler PointerCanceledEventHandler;
private double startY = 0;
private double moveY = 0;
public GesturePage()
{
this.InitializeComponent();
_GestureRecognizer = new GestureRecognizer();
_GestureRecognizer.GestureSettings = GestureSettings.ManipulationTranslateY;
_GestureRecognizer.ManipulationStarted += _GestureRecognizer_ManipulationStarted;
_GestureRecognizer.ManipulationUpdated += _GestureRecognizer_ManipulationUpdated;
_GestureRecognizer.ManipulationCompleted += _GestureRecognizer_ManipulationCompleted;
PointerPressedEventHandler = new PointerEventHandler(_PointerPressed);
PointerMovedEventHandler = new PointerEventHandler(_PointerMoved);
PointerReleasedEventHandler = new PointerEventHandler(_PointerReleased);
PointerCanceledEventHandler = new PointerEventHandler(_PointerCanceled);
this.AddHandler(UIElement.PointerPressedEvent, PointerPressedEventHandler, true);
this.AddHandler(UIElement.PointerMovedEvent, PointerMovedEventHandler, true);
this.AddHandler(UIElement.PointerReleasedEvent, PointerReleasedEventHandler, true);
this.AddHandler(UIElement.PointerCanceledEvent, PointerCanceledEventHandler, true);
}
private void _GestureRecognizer_ManipulationStarted(GestureRecognizer sender, ManipulationStartedEventArgs args)
{
startY = args.Position.Y;
}
private void _GestureRecognizer_ManipulationUpdated(GestureRecognizer sender, ManipulationUpdatedEventArgs args)
{
moveY += Math.Abs(args.Delta.Translation.Y);
}
private void _GestureRecognizer_ManipulationCompleted(GestureRecognizer sender, ManipulationCompletedEventArgs args)
{
if (moveY >= 50)
{
// Can be understood as sliding a distance
if (startY <= 10)
{
// head to foot
}
else if (startY >= Window.Current.Bounds.Height - 10)
{
// foot to head
}
startY = 0;
MoveY = 0;
}
}
private void _PointerPressed(object sender, PointerRoutedEventArgs e)
{
var pointer = e.GetCurrentPoint(this);
_GestureRecognizer.ProcessDownEvent(pointer);
}
private void _PointerMoved(object sender, PointerRoutedEventArgs e)
{
var pointers = e.GetIntermediatePoints(this);
_GestureRecognizer.ProcessMoveEvents(pointers);
}
private void _PointerCanceled(object sender, PointerRoutedEventArgs e)
{
var pointer = e.GetCurrentPoint(this);
_GestureRecognizer.CompleteGesture();
}
private void _PointerReleased(object sender, PointerRoutedEventArgs e)
{
var pointer = e.GetCurrentPoint(this);
_GestureRecognizer.ProcessUpEvent(pointer);
}
Fingers, mouse, and pens trigger Pointer related events when they tap the screen. The purpose of the above code is to capture the Pointer event and pass it to GestureRecognizer for processing.
Here is the document
Best regards.

Related

WPF DragMove() causes issues

I'm trying to figure out if there's an elegant solution to the problem I've been faced with.
So basically, I designed a borderless loading splash screen which is completely movable via dragging. I find that this happens if the splash screen gets hidden via Hide(), then displays a window via ShowDialog() with the owner set to the splash screen. Things get extremely buggy, but only if you're in mid-drag (with left mouse button down). You become unable to click or move anything, even Visual Studio becomes unresponsive unless you explicitly alt-tab out of the application.
Considering I know when I'm going to spawn the window, I was thinking maybe there'd be a way to cancel the DragMove operation, but I'm having no luck. What I've figured out is that DragMove is synchronous, so I'd guess it'd have to be cancelled from a different thread or in an event callback.
Edit:
public partial class Window_Movable : Window
{
public Window_Movable()
{
InitializeComponent();
}
public Boolean CanMove { get; set; } = true;
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (CanMove == false)
return;
Task.Factory.StartNew(() => {
System.Threading.Thread.Sleep(1000);
Dispatcher.Invoke(() => {
Hide();
new Window_Movable() {
Title = "MOVABLE 2",
CanMove = false,
Owner = this
}.ShowDialog();
});
});
DragMove();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("DING");
}
}
I had the same problem and found out that DragMove() method is a problem.
https://groups.google.com/forum/#!topic/wpf-disciples/7OcuXrf2whc
To solve I decided to refuse from using it and implement moving logic.
I've combined some solutions from
https://www.codeproject.com/Questions/284995/DragMove-problem-help-pls
and
C# WPF Move the window
private bool _inDrag;
private Point _anchorPoint;
private bool _iscaptured;
private void AppWindowWindowOnMouseMove(object sender, MouseEventArgs e)
{
if (!_inDrag)
return;
if (!_iscaptured)
{
CaptureMouse();
_iscaptured = true;
}
var mousePosition = e.GetPosition(this);
var mousePositionAbs = new Point
{
X = Convert.ToInt16(_appWindowWindow.Left) + mousePosition.X,
Y = Convert.ToInt16(_appWindowWindow.Top) + mousePosition.Y
};
_appWindowWindow.Left = _appWindowWindow.Left + (mousePositionAbs.X - _anchorPoint.X);
_appWindowWindow.Top = _appWindowWindow.Top + (mousePositionAbs.Y - _anchorPoint.Y);
_anchorPoint = mousePositionAbs;
}
private void AppWindowWindowOnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_inDrag)
{
_inDrag = false;
_iscaptured = false;
ReleaseMouseCapture();
}
}
private void AppWindowWindowOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_anchorPoint = e.GetPosition(this);
_anchorPoint.Y = Convert.ToInt16(_appWindowWindow.Top) + _anchorPoint.Y;
_anchorPoint.X = Convert.ToInt16(_appWindowWindow.Left) + _anchorPoint.X;
_inDrag = true;
}
I've spend all yesterday evening and find a more hacky but more functional solution. Which support Maximized state and not require manual coordinate calculation.
private bool _mRestoreForDragMove;
private void OnAppWindowWindowOnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
if (_appWindowWindow.ResizeMode != ResizeMode.CanResize &&
_appWindowWindow.ResizeMode != ResizeMode.CanResizeWithGrip)
{
return;
}
_appWindowWindow.WindowState = _appWindowWindow.WindowState == WindowState.Maximized
? WindowState.Normal
: WindowState.Maximized;
}
else
{
_mRestoreForDragMove = _appWindowWindow.WindowState == WindowState.Maximized;
SafeDragMoveCall(e);
}
}
private void SafeDragMoveCall(MouseEventArgs e)
{
Task.Delay(100).ContinueWith(_ =>
{
Dispatcher.BeginInvoke((Action)
delegate
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
_appWindowWindow.DragMove();
RaiseEvent(new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left)
{
RoutedEvent = MouseLeftButtonUpEvent
});
}
});
});
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (_mRestoreForDragMove)
{
_mRestoreForDragMove = false;
var point = PointToScreen(e.MouseDevice.GetPosition(this));
_appWindowWindow.Left = point.X - (_appWindowWindow.RestoreBounds.Width * 0.5);
_appWindowWindow.Top = point.Y;
_appWindowWindow.WindowState = WindowState.Normal;
_appWindowWindow.DragMove();
SafeDragMoveCall(e);
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_mRestoreForDragMove = false;
}
The thing is to send LeftMouseButtonUp event after a short delay to avoid blocking from DragMove()
Sources for last solve:
DragMove() and Maximize
C# WPF - DragMove and click
And one more completely different solution. To make a window movable you can use CaptionHeight of WindowChrome.
i.e.
var windowChrome =
WindowChrome.GetWindowChrome(appWindow.Window);
windowChrome.CaptionHeight = MainWindowToolbar.Height;
WindowChrome.SetWindowChrome(appWindow.Window, windowChrome);
but you should also set attached property WindowChrome.IsHitTestVisibleInChrome="True" for all controls in the window.

Button Click Not Fired on Move Event

I'm trying to move the Button inside my application, It's working fine but the ButtonClick event is not firing now.
Code :
XAML
<Button Content="Button" Height="23" HorizontalAlignment="Left"
Margin="190,108,0,0" Name="button1" VerticalAlignment="Top"
Width="75" MouseLeftButtonUp="button1_MouseLeftButtonUp"
MouseMove="button1_MouseMove" MouseUp="button1_MouseUp" Click="button1_Click"/>
C#
public MainWindow()
{
InitializeComponent();
button1.PreviewMouseUp += new MouseButtonEventHandler(button1_MouseUp);
button1.PreviewMouseLeftButtonDown += new MouseButtonEventHandler
(button1_MouseLeftButtonUp);
button1.PreviewMouseMove += new MouseEventHandler(button1_MouseMove);
}
double m_MouseX;
double m_MouseY;
public MainWindow()
{
InitializeComponent();
button1.PreviewMouseUp += new MouseButtonEventHandler(button1_MouseUp);
button1.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(button1_MouseLeftButtonUp);
button1.PreviewMouseMove += new MouseEventHandler(button1_MouseMove);
}
private void button1_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// Get the Position of Window so that it will set margin from this window
m_MouseX = e.GetPosition(this).X;
m_MouseY = e.GetPosition(this).Y;
}
private void button1_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
// Capture the mouse for border
e.MouseDevice.Capture(button1);
System.Windows.Thickness _margin = new System.Windows.Thickness();
int _tempX = Convert.ToInt32(e.GetPosition(this).X);
int _tempY = Convert.ToInt32(e.GetPosition(this).Y);
_margin = mainGrd.Margin;
// when While moving _tempX get greater than m_MouseX relative to usercontrol
if (m_MouseX > _tempX)
{
// add the difference of both to Left
_margin.Left += (_tempX - m_MouseX);
// subtract the difference of both to Left
_margin.Right -= (_tempX - m_MouseX);
}
else
{
_margin.Left -= (m_MouseX - _tempX);
_margin.Right -= (_tempX - m_MouseX);
}
if (m_MouseY > _tempY)
{
_margin.Top += (_tempY - m_MouseY);
_margin.Bottom -= (_tempY - m_MouseY);
}
else
{
_margin.Top -= (m_MouseY - _tempY);
_margin.Bottom -= (_tempY - m_MouseY);
}
mainGrd.Margin = _margin;
m_MouseX = _tempX;
m_MouseY = _tempY;
}
}
private void button1_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
e.MouseDevice.Capture(null);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("HI");
}
button1_Click never fires, any suggestions.
Is I'm doing something wrong or there is a better way to do it?
This prevents your button1_Click from firing:
e.MouseDevice.Capture(null);
I assume that you want the messagebox to show only when you click the button without dragging it.
I would remove the MouseUp event and instead use:
XAML
PreviewMouseDown="Button1_OnPreviewMouseDown"
C#
double m_MouseX;
double m_MouseY;
double m_ClickedX;
double m_ClickedY;
[...]
private void Button1_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
m_ClickedX = m_MouseX;
m_ClickedY = m_MouseY;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (m_ClickedX == m_MouseX && m_ClickedY == m_MouseY)
{
MessageBox.Show("HI");
}
}
The if statement checks if you have moved the button or not and only shows the MessageBox if the button has not been moved.

Mouse-Events are not getting fired when Mouse Button is pressed [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 9 years ago.
Improve this question
when a mouse button is pressed on a control, it doesn't fire any events on it anymore.
I need that, since i wanted to enable myself to navigate through a control by "dragging" it.
The Drag events aren't getting fired either. Don't know why it is this way. It's useless.
I need an event thats getting fired when the mouse moves. Where is it?
Edit:
Look, when you hold the left mouse-button on Google-Map, you can move on the map with your mouse movement. I want to do the same thing with my UserControl. I overrided the OnPaint-Method so it would simply displays a grid. I have also implemented functions to move around with keys. It all works so far. Now i want to move around with the mouse by holding down the left mouse-button and move it. It should be easy and obvious, but it isn't.
So i subscribed all the mouse- and drag-events. Like that:
public partial class GameBoard : UserControl
{
private int m_CellWidth = 5;
private int m_CellHeight = 5;
private Point m_Position = Point.Empty;
private Point m_MousePoint = Point.Empty;
public GameBoard()
{
InitializeComponent();
ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Point firstPoint = new Point(m_Position.X % m_CellWidth, m_Position.Y % m_CellHeight);
int countVisibleCols = (int)Math.Ceiling((double)((double)Width / (double)m_CellWidth));
int countVisibleRows = (int)Math.Ceiling((double)((double)Height / (double)m_CellHeight));
Pen artistsPen = new Pen(Brushes.Black);
for (int i = 0; i < countVisibleCols; i++)
{
Point startPoint = new Point(firstPoint.X + i * m_CellWidth, 0);
Point endPoint = new Point(firstPoint.X + i * m_CellWidth, Height);
e.Graphics.DrawLine(artistsPen, startPoint, endPoint);
}
for (int i = 0; i < countVisibleRows; i++)
{
Point startPoint = new Point(0, firstPoint.Y + i * m_CellHeight);
Point endPoint = new Point(Width, firstPoint.Y + i * m_CellHeight);
e.Graphics.DrawLine(artistsPen, startPoint, endPoint);
}
}
private void GameBoard_MouseUp(object sender, MouseEventArgs e)
{
}
private void GameBoard_MouseMove(object sender, MouseEventArgs e)
{
}
private void GameBoard_MouseLeave(object sender, EventArgs e)
{
}
private void GameBoard_MouseHover(object sender, EventArgs e)
{
}
private void GameBoard_MouseEnter(object sender, EventArgs e)
{
}
private void GameBoard_MouseDown(object sender, MouseEventArgs e)
{
}
private void GameBoard_MouseDoubleClick(object sender, MouseEventArgs e)
{
}
private void GameBoard_MouseClick(object sender, MouseEventArgs e)
{
}
private void GameBoard_DragDrop(object sender, DragEventArgs e)
{
}
private void GameBoard_DragEnter(object sender, DragEventArgs e)
{
}
private void GameBoard_DragOver(object sender, DragEventArgs e)
{
}
private void GameBoard_DragLeave(object sender, EventArgs e)
{
}
}
(Actual subscriptions happens in the designer.)
The Problem is: If the left mouse-button has beeing clicked & hold on my control, NOT ONE of those events are getting fired anymore. So i don't know how to implement the desired feature.
Use the MouseMove() event. You can determine if the Left button is down during a move using the e.Button parameter. Here's an example with a Button:
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
this.Text = "Left: " + e.X.ToString() + ", " + e.Y.ToString();
}
else if (e.Button == System.Windows.Forms.MouseButtons.None)
{
this.Text = e.X.ToString() + ", " + e.Y.ToString();
}
}
Not all controls behave the same, however. Give more details about exactly which control you're trying to use and how.
In the Visual Studio designer for a form, there's an Events button in the Properties window of a component that typically looks like a lightning bolt. You can use this to tie events to functions. Could this be missing?

WPF contextMenu control for bring forward and send backward

Having trouble with something here which I'm hoping is actually simple.
I have a custom UserControl in WPF which allows me to display an image. When the program is running a user can add this UserControl as many times as they like to a canvas. In effect a simple image viewer where they can add and move images about.
I would like to be able to right click these images open a contextMenu and then choose send backward of bring forward and the images would then change z order depending which menu choice was clicked.
I have the user control set up with the contextMenu so I just need to know the code for changing the z order of this userControl...
Any help is much appreciated :)
namespace StoryboardTool
{
/// <summary>
/// Interaction logic for CustomImage.xaml
/// </summary>
public partial class CustomImage : UserControl
{
private Point mouseClick;
private double canvasLeft;
private double canvasTop;
public CustomImage()
{
InitializeComponent();
cusImageControl.SetValue(Canvas.LeftProperty, 0.0);
cusImageControl.SetValue(Canvas.TopProperty, 0.0);
}
public void chooseImage()
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Choose Image to Add";
if (ofd.ShowDialog() == true)
{
BitmapImage bImage = new BitmapImage();
bImage.BeginInit();
bImage.UriSource = new Uri(ofd.FileName);
bImage.EndInit();
image.Width = bImage.Width;
image.Height = bImage.Height;
image.Source = bImage;
image.Stretch = Stretch.Fill;
}
}
private void cusImageControl_LostMouseCapture(object sender, MouseEventArgs e)
{
((CustomImage)sender).ReleaseMouseCapture();
}
private void cusImageControl_MouseUp(object sender, MouseButtonEventArgs e)
{
((CustomImage)sender).ReleaseMouseCapture();
cusImageControl.Cursor = Cursors.Arrow;
}
private void cusImageControl_MouseMove(object sender, MouseEventArgs e)
{
if ((((CustomImage)sender).IsMouseCaptured) && (cusImageControl.Cursor == Cursors.SizeAll))
{
Point mouseCurrent = e.GetPosition(null);
double Left = mouseCurrent.X - mouseClick.X;
double Top = mouseCurrent.Y - mouseClick.Y;
mouseClick = e.GetPosition(null);
((CustomImage)sender).SetValue(Canvas.LeftProperty, canvasLeft + Left);
((CustomImage)sender).SetValue(Canvas.TopProperty, canvasTop + Top);
canvasLeft = Canvas.GetLeft(((CustomImage)sender));
canvasTop = Canvas.GetTop(((CustomImage)sender));
}
else if ((((CustomImage)sender).IsMouseCaptured) && (cusImageControl.Cursor == Cursors.SizeNWSE))
{
/*Point mouseCurrent = e.GetPosition(null);
cusImageControl.Height = cusImageControl.canvasTop + mouseClick.Y;
cusImageControl.Width = cusImageControl.canvasLeft + mouseClick.X;
mouseClick = e.GetPosition(null);*/
}
}
private void cusImageControl_MouseDown(object sender, MouseButtonEventArgs e)
{
mouseClick = e.GetPosition(null);
canvasLeft = Canvas.GetLeft(((CustomImage)sender));
canvasTop = Canvas.GetTop(((CustomImage)sender));
((CustomImage)sender).CaptureMouse();
}
private void ContextMenuBringForward_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Bring Forward");
}
private void ContextMenuSendBackward_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Send Backward");
}
private void ContextMenuMove_Click(object sender, RoutedEventArgs e)
{
cusImageControl.Cursor = Cursors.SizeAll;
}
private void ContextMenuResize_Click(object sender, RoutedEventArgs e)
{
cusImageControl.Cursor = Cursors.SizeNWSE;
}
}
}
See Panel attached property Canvas.SetZIndex. Change z-Index of all elements to 0, and z-Index of your right-clicked control to 1.
void mouseUp(object sender, MouseButtonEventArgs e)
{
foreach (var child in yourCanvas.Children) Canvas.SetZIndex(child, 0);
Canvas.SetZIndex((UIElement)sender, 1);
}
The following code works where selected is defined as my UserControl and set in the mouseDown event.
private void ContextMenuSendBackward_Click(object sender, RoutedEventArgs e)
{
Canvas parent = (Canvas)LogicalTreeHelper.GetParent(this);
foreach (var child in parent.Children)
{
Canvas.SetZIndex((UIElement)child, 0);
}
Canvas.SetZIndex(selected, 1);
}
Thanks to voo for all his help.

Program wont close and aforge camera keeps running, threading trouble

I have a bit strange problem, which I find hard to debug
Sometimes I can't close my program and it freezes when I try to close it.
I made a large program for video image recognition.
I made a special button to close the camera. This button works with this by calling a function below, and it indeed, it does work.
private void exitcamera()
{
FinalVideo.SignalToStop();
FinalVideo.WaitForStop();
FinalVideo = null;
}
Notice that the original video was started like this
private void buttonStartCamera_Click(object sender, EventArgs e)
{
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
FinalVideo.DesiredFrameSize = new System.Drawing.Size(640, 480);
FinalVideo.DesiredFrameRate = 90;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.ProvideSnapshots = true; //snapshots
FinalVideo.Start();
}
Now my problem seems (and this is a guess because I can't debug this moment)
That some thread is still active wanting to update the main form with data.
However it might not be able to do so since that one is closing.
I think something like that is going on so I wrote on the main application form
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
// Thread.Sleep(1000); // not sure about these delays might help syncing threads
ExitCamera();
Thread.Sleep(1000);
}
However with that last code in place the program has even more trouble to exit.
I would like to send the subthreads an exit, but I dont know their names (if they have a name), I dont know how to list them or to instruct them to stop they are in another dll not my part of the code. From some dll's I dont have the code.
So are there ways of listing sub threads and then close them one by one, if one presses the uppercorner right cross to exit the application?
Well I managed to debug the program, and finally found what caused the problem.
It is a little bit strange since as a button I could stop the camera using the exitcamera function.
However, inside a _formclosing event the same routine didn't work although it worked after I had marked out the waitforstop function.
private void exitcamera()
{
FinalVideo.SignalToStop();
// FinalVideo.WaitForStop(); << marking out that one solved it
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame); // as sugested
FinalVideo = null;
}
I am still a bit confused about it, why this wont work in case a closing event. But it seems to be solved by this.
Maybe you have memory leaks problems caused by the event. You could try to unhook the event while exiting the programm :
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame);
Maybe this will help.
This helped with another problem when I wanted to show a preview, click a "grab" button, change the resolution of the camera from low res to high res, grab an image, and then change back to low res for the preview. Here is what worked, even though I had to abandon it because stopping and starting the camera reset the auto exposure so the picture was awful on the grabbed image:
using AForge.Video;
using AForge.Video.DirectShow;
public partial class Form1 : Form
{
private int PreviewRefreshDelayMS = 40;
private FilterInfoCollection VideoCaptureDevices;
private VideoCaptureDevice CustomerWebcam;
private int CustomerWebcam_CapabilitiesIndexMin;
private int CustomerWebcam_CapabilitiesIndexMax;
private bool bCustomerWebcam_capture;
private Bitmap CustomerWebcam_bitmap;
private System.DateTime CustomerWebcam_nextframetime = DateTime.Now;
public Form1()
{
InitializeComponent();
}
// Some good info to make this more robust
// http://haryoktav.wordpress.com/2009/03/21/webcam-in-c-aforgenet/
//
private void button1_Click(object sender, EventArgs e)
{
CustomerWebcam = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
CustomerWebcam.NewFrame += new NewFrameEventHandler(CustomerWebcam_NewFrame);
int indexMin = -1;
int MinPixels = 0;
int indexMax = -1;
int MaxPixels = 0;
for (int i = 0; i < CustomerWebcam.VideoCapabilities.Length; i++)
{
int pixels = CustomerWebcam.VideoCapabilities[i].FrameSize.Height * CustomerWebcam.VideoCapabilities[i].FrameSize.Width;
if (indexMin == -1) { indexMin = i; MinPixels = pixels; }
if (indexMax == -1) { indexMax = i; MaxPixels = pixels; }
if (pixels < MinPixels) { indexMin = i; MinPixels = pixels; }
if (pixels > MaxPixels) { indexMax = i; MaxPixels = pixels; }
}
CustomerWebcam_CapabilitiesIndexMin = indexMin;
CustomerWebcam_CapabilitiesIndexMax = indexMax;
CustomerWebcam.VideoResolution = CustomerWebcam.VideoCapabilities[indexMin];
CustomerWebcam.DisplayPropertyPage(IntPtr.Zero);
CustomerWebcam.Start();
}
void CustomerWebcam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (CustomerWebcam_bitmap != null)
{
CustomerWebcam_bitmap.Dispose();
CustomerWebcam_bitmap = null;
}
if (bCustomerWebcam_capture)
{
CustomerWebcam_bitmap = (Bitmap)eventArgs.Frame.Clone();
System.Random rnd = new Random();
CustomerWebcam_bitmap.Save("img" + Convert.ToString((int)(rnd.NextDouble() * 10000000)) + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
bCustomerWebcam_capture = false;
((Bitmap)eventArgs.Frame).Dispose();
}
else
if (DateTime.Now > CustomerWebcam_nextframetime)
{
CustomerWebcam_bitmap = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = CustomerWebcam_bitmap;
CustomerWebcam_nextframetime = DateTime.Now.AddMilliseconds(PreviewRefreshDelayMS);
((Bitmap)eventArgs.Frame).Dispose();
}
}
private void Form1_Load(object sender, EventArgs e)
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo VideoCaptureDevice in VideoCaptureDevices)
{
comboBox1.Items.Add(VideoCaptureDevice.Name);
}
comboBox1.SelectedIndex = 0;
}
private void button2_Click(object sender, EventArgs e)
{
CustomerWebcam.SignalToStop();
CustomerWebcam = null;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (!(CustomerWebcam == null))
if (CustomerWebcam.IsRunning)
{
CustomerWebcam.SignalToStop();
CustomerWebcam = null;
}
}
private void button4_Click(object sender, EventArgs e)
{
bCustomerWebcam_capture = true;
}
}
One other thing to mention ... the AForge library was the most consistent way I was able to find for using a webcam to grab a still image and save as a JPEG without delving into the world of Windows 8 metro apps. I was hoping to use OpenCV.NET, or just the regular .NET API with DirectShow or WIA, but this was the most simple and it worked for me.
And here are some good samples that were hard to find but very useful: https://github.com/mdavid/aforge.net
I was dealing with this problem. Here is a simple way to stop the camera and close Win Form.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (FinalVideo != null)
{
if (FinalVideo.IsRunning)
{
FinalVideo.SignalToStop();
FinalVideo = null;
}
}
}
In my situation WaitForStop() was needed, but the code execution was deading inside the method.
I've replaced it right after the call to SignalToStop(), with:
while (m_Device.IsRunning) { }
This is the code involved on the AForge library:
public bool IsRunning
{
get
{
if (this.thread != null)
{
if (!this.thread.Join(0))
{
return true;
}
this.Free();
}
return false;
}
}
public void WaitForStop()
{
if (this.thread != null)
{
this.thread.Join();
this.Free();
}
}
Edit: this didn't fix the hang the 100% of times. Sometimes a call to a com object (mediaControl.Stop();) on the WorkerThread() method just took forever.
Avoid direct interaction with the form - hope to have a better solution than timer but solves problem. I
Static helper class
public static Bitmap StaticBitmap = new Bitmap(100,100);
Form
public void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
lock (StaticHelper.StaticBitmap)
{
using (Bitmap b = (Bitmap)eventArgs.Frame)
{
StaticHelper.StaticBitmap = (Bitmap)b.Clone();
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (StaticHelper.StaticBitmap)
{
pictureBox1.Image = (Bitmap)StaticHelper.StaticBitmap.Clone();
}
}
This will destroy your problem ( I have had this problem, i tried)
using System.Threading;
bool photo_was_taken = false;
private void buttonStartCamera_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(exitcamera));
thread.Start();
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[comboBox1.SelectedIndex].MonikerString);
FinalVideo.DesiredFrameSize = new System.Drawing.Size(640, 480);
FinalVideo.DesiredFrameRate = 90;
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.ProvideSnapshots = true; //snapshots
FinalVideo.Start();
}
private void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
// what you want to do ( your code is here )
photo_was_taken = true;
}
private void exitcamera()
{
while (!photo_was_taken)
{
Thread.Sleep(5); // you can change wait milliseconds
}
FinalVideo.SignalToStop();
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame);
//FinalVideo.WaitForStop();
while (FinalVideo.IsRunning)
{
FinalVideo.Stop();
// FinalVideo = null; >> // that is not condition
}
}
This is what you need, 100% working solutions:
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
Invoke((MethodInvoker) delegate
{
_videoSource.SignalToStop();
_videoSource.WaitForStop();
});
}
Please, let me add my working solution on closing a webcam with the wonderful library AForge.NET. It´s a pitty it development has been abandoned.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (videoCaptureSource != null)
{
while (videoCaptureSource.IsRunning) // Perhaps you need to limit the number of iterations
{
videoCaptureSource.SignalToStop();
videoCaptureSource.WaitForStop();
if (videoSourcePlayer != null)
{
videoSourcePlayer.SignalToStop();
videoSourcePlayer.WaitForStop();
//videoSourcePlayer.NewFrame -= new NewFrameEventHandler(videoSourcePlayer_NewFrame); // Uncomment this line if you have added an event handler
}
Thread.Sleep(3000);
}
videoCaptureSource = null;
videoDevices = null;
videoSourcePlayer = null;
}
}
When I only needed the frame attaching an event handler to the VideoCaptureDevice (not the VideoSourcePlayer) I couldn´t stop the video from the VideoCaptureDevice, instead I used an invisible VideoSourcePlayer and stopped it from there.
i tried some solution, but nothing work.
i partial solved adding a thread sleep after WaitForStop
if (FinalVideo != null)
{
if (FinalVideo.IsRunning)
{
FinalVideo.SignalToStop();
Thread.Sleep(1000);
}
}
if i try to call Stop application will be freeze

Categories

Resources