So I'm making a Kinect application using buttons, and to navigate the app, I'm making new windows for each button. I'm come across an issue I haven't been able to find any help at all on, and would appreciate any help.
So to open the new window, I'm using this:
private void button1_Click(object sender, RoutedEventArgs e)
{
//SUPPOSED to uninitialize the Kinect
UninitializeKinectSensor(this.Kinect;
//To open the new window
Window1 newwindow = new Window1();
newwindow.Show();
//To close the first window...
Close();
{
SO that one line is supposed to uninitialize the Kinect so it'll be free for the new window to use, but when it goes to the new window, the Kinect freezes. If I use the mouse to go back to the first window, it works on the first window again, which it shouldn't.
I also added in this line in the initialization phase
public Window1()
{
//Other init code is here, but this is the line I added. It doesn't seem to do anything.
InitializeKinectSensor(this.Kinect);
}
Any help is greatly appreciated!! I'm sure it's something simple and I just failed miserably haha XD
Do you really have to create a new window instead of using pages?
In your MainWindow you create a frame that takes all the window and use this frame to navigate between pages. This way, you'll keep the focus of the kinect in your whole application.
Depends alot on what UninitializeKinectSensor is actually doing. Just as a quick fix, though, you can try calling uninitialize on a background worker and see if that helps at all.
Instead of using the "Show()" use "ShowDialog()".It's better if you can create a static class or method to initialize and uninitialized kinect.
public static void start()
{
KinectSensor.KinectSensors.StatusChanged += kinectSensorsStatusChanged;
DiscoverSensor();
}
private static void kinectSensorsStatusChanged(object sender, StatusChangedEventArgs e)
{
KinectSensor oldSensor = Kinect;
if (oldSensor != null)
{
UninitializeKinect();
}
var status = e.Status;
if (Kinect == null)
{
//updateStatus(status);
if (e.Status == KinectStatus.Connected)
{
Kinect = e.Sensor;
DiscoverSensor();
}
}
else
{
if (Kinect == e.Sensor)
{
//updateStatus(status);
if (e.Status == KinectStatus.Disconnected ||
e.Status == KinectStatus.NotPowered)
{
Kinect = null;
sensorConflict = false;
DiscoverSensor();
}
}
}
}
private static DispatcherTimer readyTimer;
private static void UninitializeKinect()
{
if (speechRecognizer != null && Kinect != null)
{
Kinect.AudioSource.Stop();
Kinect.SkeletonFrameReady -= kinect_SkeletonFrameReady;
Kinect.SkeletonStream.Disable();
Kinect.Stop();
//this.FrameSkeletons = null;
speechRecognizer.RecognizeAsyncCancel();
speechRecognizer.RecognizeAsyncStop();
}
if (readyTimer != null)
{
readyTimer.Stop();
readyTimer = null;
}
}
Related
I want to capture the OK Button's Click event on a MessageBox shown by another WinForms application.
I want to achieve this using UI Automation. After some research, I have found that IUIAutomation::AddAutomationEventHandler will do the work for me.
Though, I can capture the Click event of any other button, I'm unable to capture a Click event of the MessageBox.
My code is as follows:
var FindDialogButton = appElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "OK"));
if (FindDialogButton != null)
{
if (FindDialogButton.GetSupportedPatterns().Any(p => p.Equals(InvokePattern.Pattern)))
{
Automation.AddAutomationEventHandler(InvokePattern.InvokedEvent, FindDialogButton, TreeScope.Element, new AutomationEventHandler(DialogHandler));
}
}
private void DialogHandler(object sender, AutomationEventArgs e)
{
MessageBox.Show("Dialog Button clicked at : " + DateTime.Now);
}
EDIT:
My Complete code is as follows:
private void DialogButtonHandle()
{
AutomationElement rootElement = AutomationElement.RootElement;
if (rootElement != null)
{
System.Windows.Automation.Condition condition = new PropertyCondition
(AutomationElement.NameProperty, "Windows Application"); //This part gets the handle of the Windows application that has the MessageBox
AutomationElement appElement = rootElement.FindFirst(TreeScope.Children, condition);
var FindDialogButton = appElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "OK")); // This part gets the handle of the button inside the messagebox
if (FindDialogButton != null)
{
if (FindDialogButton.GetSupportedPatterns().Any(p => p.Equals(InvokePattern.Pattern)))
{
Automation.AddAutomationEventHandler(InvokePattern.InvokedEvent, FindDialogButton, TreeScope.Element, new AutomationEventHandler(DialogHandler)); //Here I am trying to catch the click of "OK" button inside the MessageBox
}
}
}
}
private void DialogHandler(object sender, AutomationEventArgs e)
{
//On Button click I am trying to display a message that the button has been clicked
MessageBox.Show("MessageBox Button Clicked");
}
I tried to keep this procedure as generic as possible, so that it will work whether the application you're watching is already running when your app is started or not.
You just need to provide the watched Application's Process Name or its Main Window Title to let the procedure identify this application.
Use one of these Fields and the corresponding Enumerator:
private string appProcessName = "theAppProcessName"; and
FindWindowMethod.ProcessName
// Or
private string appWindowTitle = "theAppMainWindowTitle"; and
FindWindowMethod.Caption
passing these values to the procedure that starts the watcher, e.g., :
StartAppWatcher(appProcessName, FindWindowMethod.ProcessName);
As you can see - since you tagged your question as winforms - this is a complete Form (named frmWindowWatcher) that contains all the logic required to perform this task.
How does it work:
When you start frmWindowWatcher, the procedure verifies whether the watched application (here, identified using its Process name, but you can change the method, as already described), is already running.
If it is, it initializes a support class, ElementWindow, which will contain some informations about the watched application.
I added this support class in case you need to perform some actions if the watched application is already running (in this case, the ElementWindow windowElement Field won't be null when the StartAppWatcher() method is called). These informations may also be useful in other cases.
When a new Windows is opened in the System, the procedure verifies whether this Window belongs to the watched application. If it does, the Process ID will be the same. If the Windows is a MessageBox (identified using its standard ClassName: #32770) and it belongs to the watched Application, an AutomationEventHandler is attached to the child OK Button.
Here, I'm using a Delegate: AutomationEventHandler DialogButtonHandler for the handler and an instance Field (AutomationElement msgBoxButton) for the Button Element, because these references are needed to remove the Button Click Handler when the MessageBox is closed.
When the MessageBox's OK Button is clicked, the MessageBoxButtonHandler method is called. Here, you can determine which action to take at this point.
When the frmWindowWatcher Form is closed, all Automation Handlers are removed, calling the Automation.RemoveAllEventHandlers() method, to provide a final clean up and prevent your app from leaking resources.
using System.Diagnostics;
using System.Linq;
using System.Windows.Automation;
using System.Windows.Forms;
public partial class frmWindowWatcher : Form
{
AutomationEventHandler DialogButtonHandler = null;
AutomationElement msgBoxButton = null;
ElementWindow windowElement = null;
int currentProcessId = 0;
private string appProcessName = "theAppProcessName";
//private string appWindowTitle = "theAppMainWindowTitle";
public enum FindWindowMethod
{
ProcessName,
Caption
}
public frmWindowWatcher()
{
InitializeComponent();
using (var proc = Process.GetCurrentProcess()) {
currentProcessId = proc.Id;
}
// Identify the application by its Process name...
StartAppWatcher(appProcessName, FindWindowMethod.ProcessName);
// ... or by its main Window Title
//StartAppWatcher(appWindowTitle, FindWindowMethod.Caption);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
Automation.RemoveAllEventHandlers();
base.OnFormClosed(e);
}
private void StartAppWatcher(string elementName, FindWindowMethod method)
{
windowElement = GetAppElement(elementName, method);
// (...)
// You may want to perform some actions if the watched application is already running when you start your app
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement,
TreeScope.Subtree, (elm, e) => {
AutomationElement element = elm as AutomationElement;
try
{
if (element == null || element.Current.ProcessId == currentProcessId) return;
if (windowElement == null) windowElement = GetAppElement(elementName, method);
if (windowElement == null || windowElement.ProcessId != element.Current.ProcessId) return;
// If the Window is a MessageBox generated by the watched app, attach the handler
if (element.Current.ClassName == "#32770")
{
msgBoxButton = element.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.NameProperty, "OK"));
if (msgBoxButton != null && msgBoxButton.GetSupportedPatterns().Any(p => p.Equals(InvokePattern.Pattern)))
{
Automation.AddAutomationEventHandler(
InvokePattern.InvokedEvent, msgBoxButton, TreeScope.Element,
DialogButtonHandler = new AutomationEventHandler(MessageBoxButtonHandler));
}
}
}
catch (ElementNotAvailableException) {
// Ignore: this exception may be raised if you show a modal dialog,
// in your own app, that blocks the execution. When the dialog is closed,
// AutomationElement element is no longer available
}
});
Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, AutomationElement.RootElement,
TreeScope.Subtree, (elm, e) => {
AutomationElement element = elm as AutomationElement;
if (element == null || element.Current.ProcessId == currentProcessId || windowElement == null) return;
if (windowElement.ProcessId == element.Current.ProcessId) {
if (windowElement.MainWindowTitle == element.Current.Name) {
windowElement = null;
}
}
});
}
private void MessageBoxButtonHandler(object sender, AutomationEventArgs e)
{
Console.WriteLine("Dialog Button clicked at : " + DateTime.Now.ToString());
// (...)
// Remove the handler after, since the next MessageBox needs a new handler.
Automation.RemoveAutomationEventHandler(e.EventId, msgBoxButton, DialogButtonHandler);
}
private ElementWindow GetAppElement(string elementName, FindWindowMethod method)
{
Process proc = null;
try {
switch (method) {
case FindWindowMethod.ProcessName:
proc = Process.GetProcessesByName(elementName).FirstOrDefault();
break;
case FindWindowMethod.Caption:
proc = Process.GetProcesses().FirstOrDefault(p => p.MainWindowTitle == elementName);
break;
}
return CreateElementWindow(proc);
}
finally {
proc?.Dispose();
}
}
private ElementWindow CreateElementWindow(Process process) =>
process == null ? null : new ElementWindow(process.ProcessName) {
MainWindowTitle = process.MainWindowTitle,
MainWindowHandle = process.MainWindowHandle,
ProcessId = process.Id
};
}
Support class, used to store informations on the watched application:
It's initialized using the App's Process Name:
public ElementWindow(string processName)
but of course you can change it as required, using the Window Title as described before, or even remove the initialization's argument if you prefer (the class just need to not be null when the watched Application has been detected and identified).
using System.Collections.Generic;
public class ElementWindow
{
public ElementWindow(string processName) => this.ProcessName = processName;
public string ProcessName { get; set; }
public string MainWindowTitle { get; set; }
public int ProcessId { get; set; }
public IntPtr MainWindowHandle { get; set; }
}
The problem is with the button:contains('Deal') selector, the button containing deal does exist on the page and Watin can find it without problems when running in main thread.
// Add bet, deal cards and wait for animation
private void dealCards()
{
// Start the game if chip exists
if (browser.Image(Find.BySrc(chipURL)).Exists)
{
browser.Image(Find.BySrc(chipURL)).Click();
// This is where the thread stops
browser.Button(Find.BySelector("button:contains('Deal')")).Click();
Thread.Sleep(dealCardsAnimationTime);
if (Convert.ToInt32(browser.Span(Find.ByClass("player-points")).Text) == 21)
{
consoleTextBox.AppendText("You won by blackjack.");
gameOver = true;
}
return;
}
}
Update:
Browser is a Internet Explore window that I interact with using WatiN, other than the UI changes, the problem seems to be that WatiN can't find the button.
However it's still somewhat related to multithreading, as the same code works fine without multithreading and the element that it's searching for does exist.
Update 2: Changed title and description of problem as the old one appeared to be unrelated.
Context ( in case it's necessary )
// When bet button is clicked
private void button2_Click(object sender, EventArgs e)
{
blackjackThread = new Thread(blackjackGame);
if (dealInProgress == false)
{
blackjackThread.Start();
// blackjackGame();
}
}
// Blackjack deal handler
private void blackjackGame()
{
consoleTextBox.AppendText("\r\n");
resetVariables();
dealCards();
if (gameOver == true)
{
checkResult();
dealInProgress = false;
blackjackThread.Abort();
return;
}
checkCards();
logPoints();
while (gameOver == false)
{
botAction();
}
checkResult();
dealInProgress = false;
blackjackThread.Abort();
return;
}
I am new to WPF and have been hunting for an answer, surely this is not difficult?
I have created a main window with links to multiple windows, and I want them to run modelessly alongside one another, but I don't want to open multiple instances of the SAME window.
In simple terms, I can have Windows A, B, C open at once, but not Windows, A, A, B, C, C.
I need to implement a check for the window I'm trying to open (in this case, EditSettings).
If open - activate it
if not open, open it.
I have the following code in Main, which is not working.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
EditSettings winEditSettings = new EditSettings();
string isOpen = null;
if (isOpen == "true")
{
winEditSettings.Activate();
}
else
{
winEditSettings.Show();
isOpen = "true";
}
}
}
Now I know what's wrong with this logic - every time I press the button to open EditSettings, it's setting isOpen to null again. If I don't set a value to isOpen, the If condition breaks.
I could initialise the variable 'isOpen' as a public variable outside the MenuItem_Click method, but then I think I would need an isOpen variable for each window I create!! Surely there is a better way?
The other option I tried is:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
EditSettings winEditSettings = new EditSettings();
if (winEditSettings.IsLoaded)
{
winEditSettings.Activate();
}
else { winEditSettings.Show(); }
I can't figure out why this isn't working, I tried isVisible, isLoaded, isActive - nothing is stopping the window from opening more than once. Thank you for the help!
There are people who'll perhaps throw a fit at the idea, but whenever I've needed to do this, I made the child window objects part of the application. Then, in your MenuItem_Click(), test if winEditSettings is null, instead.
It's still a member variable for each window (like your provisional isOpen solution), but having the window objects available can have advantages later, if you need to bridge information between the windows. In my cases, we wanted to be able to close all the child windows together, which (most trivially) meant keeping track of those objects in a central location.
Alternatively, if you want the setup completely decoupled, you could take a singleton-like approach and put the logic into your child window classes. Specifically, you could call EditSettings.Activate and let the class keep track of whether a window needs to be created or the existing window merely Show()n.
If I were handed your code to rewrite, I'd move it something like this:
private static EditSettings winEditSettings = null;
public static void WakeUp()
{
if (winEditSettings == null)
{
winEditSettings = new EditSettings();
}
winEditSettings.Activate(); // This may need to be inside the block above
winEditSettings.Show();
}
Both of those are part of the class (static), rather than an instance. Your application object therefore calls EditSettings.WakeUp() inside the original MenuItem_Click(), and never actually sees the child window, itself.
If you change your mind about the decoupled architecture later, by the way, you can add a get accessor to your winEditSettings and keep everybody fairly happy.
if (_adCst == null)
{
_adCst = new AddCustomerPage();
_adCst.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
_adCst.WindowState = System.Windows.WindowState.Normal;
_adCst.ResizeMode = System.Windows.ResizeMode.NoResize;
_adCst.Activate(); // This may need to be inside the block above
_adCst.Show();
}
else
{
if (!_adCst.IsLoaded == true)
{
_adCst = new AddCustomerPage();
_adCst.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
_adCst.WindowState = System.Windows.WindowState.Normal;
_adCst.ResizeMode = System.Windows.ResizeMode.NoResize;
_adCst.Show();
}
_adCst.Activate();
}
My suggestion would be that you set some form of a counter. This will prevent more than one instance of the window being opened.
int windowOpen = 1;
private void button_Click(object sender, RoutedEventArgs e)
{
if (windowOpen == 1)
{
WindowA winA = new WindowA();
winA.Show();
windowOpen++; //increments windowOpen by 1, windowOpen will now = 2
}
else if (windowOpen > 1)
{
MessageBox.Show("Window is already open");
}
}
I hope this helps.
For anyone else with this question, I have found another solution - which works except that it doesn't manage to bring the open window to the front (Activate). It does, however, prevent opening the same window more than once.
foreach (Window n in Application.Current.Windows)
if (n.Name == "winEditSettings")
{ winEditSettings.Activate(); }
else
{ winEditSettings.Show(); }
Can anyone speculate on why the window is not brought to the front, with Activate()?
EDIT
For others with this question, placing the winEditSettings.Activate() outside of the foreach loop does everything I'm trying to achieve:
foreach (Window n in Application.Current.Windows)
if (n.Name == "winEditSettings")
{ }
else
{ winEditSettings.Show(); }
winEditSettings.Activate();
This will stop multiple instances of the same window from opening, and will bring the window to the front if the user attempts to reopen it.
I working on a Windows Phone 7 app with Text-To-Speech capabilities. I'm using Text-To-Speech with Microsoft Translator Service and the following C# code...
// Text-To-Speech with Microsoft Translator Service (http://translatorservice.codeplex.com/)
private void TextToSpeech_Play(object sender, EventArgs e)
{
SpeechSynthesizer speech = new SpeechSynthesizer(CLIENT_ID, CLIENT_SECRET);
//string content = "This is a beautiful day!";
string language = "en";
//speech.SpeakAsync(content, language);
foreach (UIElement element in todayschapter.Children)
{
if (element is TextBlock)
{
string content = (element as TextBlock).Text;
speech.SpeakAsync(content, language);
}
}
}
In this instance, todayschapter is a StackPanel and its Children are TextBlocks. I'm wanting to simply play audio of each TextBlock, in succession. The problem is that it is play the audio of EVERY TextBlock at the same time.
I have a sneaking suspicion that the problem is SpeakAsync(), but I'm not sure. The documentation shows Speak(), but that isn't available (maybe a different version) in the Visual Studio methods helper dropdown (little thing that shows as you type - not sure what it's called).
Is there a way to make it wait for each play to finish before playing the next? Is foreach not the right choice, for this?
As always, if my code just looks stupid, please recommend better ways. I'm very much a beginner programmer.
Just use the Speak instead of the async call, since you want to have it one after another anyway.
The SpeakAsync call is indeed the problem. Unfortunately, since SpeakAsync doesn't return a Task, you can't just convert this to await SpeakAsync() (which would be the most straightforward conversion).
And, looking at the source code, it doesn't fire an event to tell when it's done. So let's add one (in SpeechSynthesizer.cs):
public event EventHandler<SpeechEventArgs> SpeakCompleted;
public void SpeakAsync(string text, string language)
{
this.GetSpeakStreamAsyncHelper(text, language, result =>
{
if (result.Error == null)
{
SoundEffect effect = SoundEffect.FromStream(result.Stream);
FrameworkDispatcher.Update();
effect.Play();
this.OnSpeakCompleted(new SpeechEventArgs(result.Error)); // added to call completion handler
}
else
{
this.OnSpeakFailed(new SpeechEventArgs(result.Error));
}
});
}
// new function
private void OnSpeakCompleted(SpeechEventArgs e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (SpeakCompleted != null)
SpeakCompleted(this, e);
});
}
Now, you'll need to handle the SpeakCompleted event and start speaking the next string.
Something like this (I haven't even compiled this, so be warned):
private Queue<string> utterances;
private SpeechSynthesizer speech;
private void TextToSpeech_Play(object sender, EventArgs e)
{
speech = new SpeechSynthesizer(CLIENT_ID, CLIENT_SECRET);
speech.SpeechCompleted += new EventHandler<SpeechEventArgs>(TextToSpeech_Completed);
foreach (UIElement element in todayschapter.Children)
{
if (element is TextBlock)
{
string content = (element as TextBlock).Text;
utterances.Enqueue(content);
}
}
TextToSpeech_Completed(null, null); // start speaking the first one
}
private void TextToSpeech_Completed(object sender, SpeechEventArgs e)
{
if (utterances.Any())
{
string contents = utterances.Dequeue();
speech.SpeakAsync(contents);
}
}
I've got a .Net 3.5 C# Winforms app. It's got no GUI as such, just a NotifyIcon with a ContextMenu.
I've tried to set the NotifyIcon to visible=false and dispose of it in the Application_Exit event, as follows:
if (notifyIcon != null)
{
notifyIcon.Visible = false;
notifyIcon.Dispose();
}
The app gets to the code inside the brackets, but throws a null ref exception when it tries to set Visible = false.
I've read in a few places to put it in the form closing event, but that code never gets hit (maybe as I don't have a form showing as such?).
Where can I put this code so it actually works? If I don't put it in, I get the annoying lingering icon in the tray until you move the mouse over it.
Cheers.
EDIT
Just something extra I've noticed...........
I'm using ClickOnce in the app.........if I just exit the app via the ContextMenu on the NotifyIcon, no exception is logged.
Just when the Application_Exit event is fired after the applicaiton has checked for an upgrade here..
private void CheckForUpdate()
{
EventLogger.Instance.LogEvent("Checking for Update");
if (ApplicationDeployment.IsNetworkDeployed && ApplicationDeployment.CurrentDeployment.CheckForUpdate())
{
EventLogger.Instance.LogEvent("Update available - updating");
ApplicationDeployment.CurrentDeployment.Update();
Application.Restart();
}
}
Does this help?
On Windows 7, I had to also set the Icon property to null. Otherwise, the icon remained in the tray's "hidden icons" popup after the application had closed. HTH somebody.
// put this inside the window's class constructor
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
private void OnApplicationExit(object sender, EventArgs e)
{
try
{
if (trayIcon != null)
{
trayIcon.Visible = false;
trayIcon.Icon = null; // required to make icon disappear
trayIcon.Dispose();
trayIcon = null;
}
}
catch (Exception ex)
{
// handle the error
}
}
This code works for me, but I don't know how you are keeping your application alive, so... without further ado:
using System;
using System.Drawing;
using System.Windows.Forms;
static class Program
{
static System.Threading.Timer test =
new System.Threading.Timer(Ticked, null, 5000, 0);
[STAThread]
static void Main(string[] args)
{
NotifyIcon ni = new NotifyIcon();
ni.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
ni.Visible = true;
Application.Run();
ni.Visible = false;
}
static void Ticked(object o) {
Application.Exit();
}
}
This is what I'm doing in WPF.
I am using this in conjunction to David Anson's Minimize to tray sample app, which lets you hook up a tray icon to a window (you may have multiple windows open).
Just added this code to the constructor for MinimizeToTrayInstance.
_window.Closed += (s, e) =>
{
if (_notifyIcon != null)
{
_notifyIcon.Visible = false;
_notifyIcon.Dispose();
_notifyIcon = null;
}
};
Sometimes Application_Exit event can be raised several times
Just put notifyIcon = null; in the end
if (notifyIcon != null)
{
notifyIcon.Visible = false;
notifyIcon.Dispose();
notifyIcon = null;
}
This code worked for me
this.Closed += (a, b) =>
{
if (notifyIcon1 != null)
{
notifyIcon1.Dispose();
notifyIcon1.Icon = null;
notifyIcon1.Visible = false;
}
};
Have you overridden the dispose method of the object where you've initialised the notifyIcon to also dispose the notifyIcon?
protected override void Dispose(bool disposing)
{
if (disposing)
{
notifyIcon.Dispose();
notifyIcon = null;
}
base.Dispose(disposing);
}
before im sorry for my bad english.
if u use "end" for exit program. then dont close notify icon.
before u will close notifyicon later close form.
u need to use me.close() for run form closing
example
its work...
notifyIcon1.Icon = Nothing
notifyIcon1.Visible = False
notifyIcon1.Dispose()
Me.Close()
but its not work
End
or only
Me.Close()