i have a small c# wpf application. The application starts hidden and i use the systemtray to show the main window. I would like to do some actions when a user unlocks the desktop. I use the SystemEvents.SessionSwitch event, bit the event doesn´t fire. I've read some posts and this event seems to be the right one for WPF applications, but it doesn't work. Are there perhaps DLLs missing or is the call to register the event too late? Is there a problem with the UI Thead?
My Application Code:
public partial class App : Application
{
private System.Windows.Forms.NotifyIcon _notifyIcon;
private bool _isExit;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch);
MainWindow = new MainWindow();
MainWindow.Closing += MainWindow_Closing;
_notifyIcon = new System.Windows.Forms.NotifyIcon();
_notifyIcon.DoubleClick += (s, args) => ShowMainWindow();
_notifyIcon.Icon = CiGCoachingClient.Properties.Resources.MyIcon;
_notifyIcon.Visible = true;
CreateContextMenu();
}
private void CreateContextMenu()
{
_notifyIcon.ContextMenuStrip =
new System.Windows.Forms.ContextMenuStrip();
//_notifyIcon.ContextMenuStrip.Items.Add("MainWindow...").Click += (s, e) => ShowMainWindow();
_notifyIcon.ContextMenuStrip.Items.Add("Exit").Click += (s, e) => ExitApplication();
}
private void ExitApplication()
{
_isExit = true;
MainWindow.Close();
_notifyIcon.Dispose();
_notifyIcon = null;
}
private void ShowMainWindow()
{
if (MainWindow.IsVisible)
{
if (MainWindow.WindowState == WindowState.Minimized)
{
MainWindow.WindowState = WindowState.Normal;
}
MainWindow.Activate();
}
else
{
MainWindow.Visibility = Visibility.Visible;
MainWindow.Show();
}
}
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
if (!_isExit)
{
e.Cancel = true;
MainWindow.Hide(); // A hidden window can be shown again, a closed one not
}
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.SessionLock)
{
//I left my desk
Console.WriteLine("i left my desk");
}
else if (e.Reason == SessionSwitchReason.SessionUnlock)
{
//I returned to my desk
Console.WriteLine("i returned to my desk");
}
}
}
What could be the reason for this? Is there a error in the code?
Regards
Sascha
Related
I have a form that is being shown using ShowDialog(), thus it is a modal window.
private void OpenForm(object sender, ItemClickEventArgs e)
{
MyForm testForm = new MyForm();
...
testForm.Enabled = true;
testForm.ShowDialog(this);
var dialogOk = testForm.DialogOK;
if(dialogOk)
{
//do some stuff 1
}
}
There is an "OK" button on the form. When OK is clicked, DialogOk is set to true. Inside MyForm class:
private void OkClick(object sender, EventArgs e)
{
// do some stuff 2
...
DialogOK = true;
Hide();
}
I need to convert this to a non-modal window. The solution seems to be to use Show() instead of ShowDialog(), but when I use Show(), the code does not stop and wait for the OK button to be clicked, so "do some stuff 1" is never called.
Using Show(), how can I keep the behavior to have "do some stuff 1" run after the OK button is clicked?
Update: Here is what I am trying now:
public partial class MyForm: XtraForm
{
public bool DialogOk;
private void OkClick(object sender, EventArgs e)
{
// do some stuff 2
...
DialogOk = true;
Close();
}
}
Method 1:
public partial class MyMainForm : XtraForm
{
private MyForm testForm;
private void OpenForm(object sender, ItemClickEventArgs e)
{
if(testForm == null)
{
testForm = new MyForm();
}
...
testForm.Enabled = true;
testForm.FormClosed += (s, a) => {
var dialogOk = testForm.DialogOk;
if (dialogOk)
{
// do some stuff 1
}
};
testForm.Show(this);
}
}
Method 2:
public partial class MyMainForm : XtraForm
{
private MyForm testForm;
private void OpenForm(object sender, ItemClickEventArgs e)
{
if(testForm == null)
{
testForm = new MyForm();
}
...
testForm.FormClosed += testForm_Closed;
testForm.Show(this);
}
private void testForm_Closed(object sender, EventArgs args)
{
var testForm = (Form)sender;
testForm.Closed -= testForm_Closed;
if (testForm.DialogResult == DialogResult.OK)
{
// do some stuff 1
}
}
}
You can handle Form.Closed event:
MyForm testForm = new MyForm();
testForm.Closed += testForm_Closed;
testForm.Show();
private void testForm_Closed(object sender, EventArgs args)
{
var testForm = (Form)sender;
testForm.Closed -= testForm_Closed;
if (testForm.DialogResult == OK)
// do some stuff 1
}
The easiest way is to move the code from OpenForm to the event handler OkClick. However, if this is not a good spot to put the code because you might want to use the same form for different tasks, you could add a handler for the FormClosed event, that is called after the form is closed and runs the code, e.g.:
private void OpenForm(object sender, ItemClickEventArgs e)
{
MyForm testForm = new MyForm();
...
testForm.Enabled = true;
testForm.FormClosed += (s, a) => {
var dialogOk = testForm.DialogOK;
if(dialogOk)
{
//do some stuff 1
}
};
testForm.Show(this);
}
You can use an async event handler tied to an TaskCompletionSource which listens and awaits the close of the form
private asyc void OpenForm(object sender, ItemClickEventArgs e) {
var source = new TaskCompletionSource<DialogResult>();
EventHandler handler = null;
handler = (s, args) => {
var form = (MyForm)s;
form.FormClosed -= handler;
source.SetResult(form.DialogResult);
}
var testForm = new MyForm();
testForm.FormClosed += handler; //subscribe
//...
testForm.Enabled = true;
testForm.Show();
var dialogOk = await source.Task;
if(dialogOk == DialogResult.Ok) {
//do some stuff 1
}
}
With that you can keep the logic in the OpenForm and allow the code to wait without blocking.
In the form when the button is clicked then all you need to do is set the dialog result and close the form.
public partial class MyForm: XtraForm {
//...
private void OkClick(object sender, EventArgs e) {
// do some stuff 2
// ...
DialogResult = DialogResult.Ok;
Cose();
}
}
This works for me, so not sure why it isn't for you (scratching head)... This form has two buttons, one which opens the same form again and another button that closes the form. The 'parent' form adds an event to the Closed event.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form1 test = new Form1();
test.FormClosed += Test_FormClosed;
test.Show();
}
private void Test_FormClosed(object sender, FormClosedEventArgs e)
{
MessageBox.Show("closed -- do something else here!");
}
private void button2_Click(object sender, EventArgs e)
{
Close();
}
}
I'm pretty new to C# and WPF, so please forgive me if my question maybe stupid. I come from the C++ world
I have an application that has a button, as long as I press the button I want to record a sounde from the microphone and when I release the button then the recording should stop. Just like the voice message in WhatsApps. I added the events PreviewMouseDown="ButtonLiveDown" and PreviewMouseUp="ButtonLiveUp" to my button and I can see that they are fired:
My main class:
m_MyLive = new AudioLive();
m_MyLive.Init(this);
private void ButtonLiveDown(object sender, MouseButtonEventArgs e)
{
m_MyLive.StartLive();
}
private void ButtonLiveUp(object sender, MouseButtonEventArgs e)
{
m_MyLive.EndLive();
}
and my Live Class:
class AudioLive
{
private MainWindow m_mainWindow;
private WaveIn m_Recorder;
private BufferedWaveProvider m_BufferedWaveProvider;
private SavingWaveProvider m_SavingWaveProvider;
private WaveOut m_Player;
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (m_Recorder != null)
{
m_Recorder.Dispose();
}
m_Recorder = null;
if (m_SavingWaveProvider != null)
{
m_SavingWaveProvider.Dispose();
}
m_SavingWaveProvider = null;
}
private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
m_BufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
public bool Init(MainWindow mainWindow)
{
m_mainWindow = mainWindow;
m_Recorder = new WaveIn();
m_Recorder.DataAvailable += RecorderOnDataAvailable;
// set up our signal chain
m_BufferedWaveProvider = new BufferedWaveProvider(m_Recorder.WaveFormat);
m_SavingWaveProvider = new SavingWaveProvider(m_BufferedWaveProvider, "live.wav");
// set up playback
m_Player = new WaveOut();
m_Player.Init(m_SavingWaveProvider);
return true;
}
public void SetMicVolume(int nVol)
{
....
}
public void StartLive()
{
SetMicVolume(100);
// begin playback & record
m_Player.Play();
m_Recorder.StartRecording();
}
public void EndLive()
{
// stop recording
m_Recorder.StopRecording();
// stop playback
m_Player.Stop();
}
}
But this doesn't work, as long as I press the button down it seems that it stops working till I release the button. From C++ I know this, as long as I press the button the system is busy with the pressed Event and can't continue to work. Is it the same with C# & WPF? If yes, is there any other way to handle my feature wish?
If I understand your question, then yes, you will have to deal with UI blocking in this case. Use a background worker to kick the event on mouse down and background worker cancellation on mouse up. Example below shows with mouseup and mouse down event handelers as oppossed to the previewmouse up and down
Updated Example to help with understanding
XAML BUTTON:
<Button x:Name="RecordBtn" Content="Button" HorizontalAlignment="Left" Margin="363,199,0,0" VerticalAlignment="Top" Width="75" MouseDown="Button_MouseDown" MouseUp="Button_MouseUp"/>
xaml code behind showing background worker kicking and holding the process:
public partial class MainWindow : Window
{
private readonly BackgroundWorker worker = new BackgroundWorker();
AudioLive m_MyLive = new AudioLive();
Stopwatch stopWatch = new Stopwatch();
public MainWindow()
{
InitializeComponent();
AddHandler(FrameworkElement.MouseDownEvent, new MouseButtonEventHandler(Button_MouseDown), true);
AddHandler(FrameworkElement.MouseUpEvent, new MouseButtonEventHandler(Button_MouseUp), true);
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerSupportsCancellation = true;
m_MyLive.Init(this);
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (!m_MyLive.IsRecordinginProgress() && !worker.CancellationPending)
{
m_MyLive.StartLive();
stopWatch.Reset();
stopWatch.Start();
}
while (m_MyLive.IsRecordinginProgress() && !worker.CancellationPending)
{
this.Dispatcher.Invoke(() =>
{
updateLabel(String.Format("{0:0.#}", TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds).TotalSeconds) + " seconds");
});
}
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
m_MyLive.EndLive();
stopWatch.Stop();
updateLabel(String.Format("{0:0.#}", TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds).TotalSeconds) + " seconds");
}
private void updateLabel(string text)
{
RecordBtn.Content = text;
}
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
worker.RunWorkerAsync();
}
private void Button_MouseUp(object sender, MouseButtonEventArgs e)
{
worker.CancelAsync();
}
}
Updated AudioLive to add property isRecording to use in our background worker:
public class AudioLive
{
private MainWindow m_mainWindow;
private WaveIn m_Recorder;
private BufferedWaveProvider m_BufferedWaveProvider;
private SavingWaveProvider m_SavingWaveProvider;
private WaveOut m_Player;
private bool isRecording { get; set; }
public bool IsRecordinginProgress()
{
return isRecording;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (m_Recorder != null)
{
m_Recorder.Dispose();
}
m_Recorder = null;
if (m_SavingWaveProvider != null)
{
m_SavingWaveProvider.Dispose();
}
m_SavingWaveProvider = null;
}
private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
m_BufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}
public bool Init(MainWindow mainWindow)
{
m_mainWindow = mainWindow;
m_Recorder = new WaveIn();
m_Recorder.DataAvailable += RecorderOnDataAvailable;
// set up our signal chain
m_BufferedWaveProvider = new BufferedWaveProvider(m_Recorder.WaveFormat);
m_SavingWaveProvider = new SavingWaveProvider(m_BufferedWaveProvider, "live.wav");
// set up playback
m_Player = new WaveOut();
m_Player.Init(m_SavingWaveProvider);
return true;
}
public void SetMicVolume(int nVol)
{
}
public void StartLive()
{
SetMicVolume(100);
// begin playback & record
m_Player.Play();
m_Recorder.StartRecording();
isRecording = true;
}
public void EndLive()
{
// stop recording
m_Recorder.StopRecording();
// stop playback
m_Player.Stop();
isRecording = false;
}
}
I'm porting an app to Univeral Windows Platform (Windows 10).
Android has a onLongPress event. Is there an equivalent for UWP?
I found there is a Holding event which I tried to use something like this:
private void Rectangle_Holding(object sender, HoldingRoutedEventArgs e)
{
if (e.HoldingState == HoldingState.Started)
{
Debug.WriteLine("Holding started!");
}
}
Problem is the event is not triggered on Windows Desktop, when mouse is used instead of touch.
Mouse input doesn't produce Holding events by default, you should use RightTapped event to show the context menu, it is triggered when user long presses in a touch device and right clicks in a mouse device.
Take a look at GestureRecognizer.Holding and Detect Simple Touch Gestures, you can achieve that using the following code
public sealed partial class MainPage : Page
{
GestureRecognizer gestureRecognizer = new GestureRecognizer();
public MainPage()
{
this.InitializeComponent();
gestureRecognizer.GestureSettings = Windows.UI.Input.GestureSettings.HoldWithMouse;
}
void gestureRecognizer_Holding(GestureRecognizer sender, HoldingEventArgs args)
{
MyTextBlock.Text = "Hello";
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
gestureRecognizer.Holding += gestureRecognizer_Holding;
}
private void Grid_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var ps = e.GetIntermediatePoints(null);
if (ps != null && ps.Count > 0)
{
gestureRecognizer.ProcessDownEvent(ps[0]);
e.Handled = true;
}
}
private void Grid_PointerMoved(object sender, PointerRoutedEventArgs e)
{
gestureRecognizer.ProcessMoveEvents(e.GetIntermediatePoints(null));
e.Handled = true;
}
private void Grid_PointerReleased(object sender, PointerRoutedEventArgs e)
{
var ps = e.GetIntermediatePoints(null);
if (ps != null && ps.Count > 0)
{
gestureRecognizer.ProcessUpEvent(ps[0]);
e.Handled = true;
gestureRecognizer.CompleteGesture();
}
}
}
I can't run my code because there is a error saying:
Cannot assign to 'OnNewLand' because it is a 'method group
This is strange because I have used the same structure as my other methods and there were no problem with them.
Here is my code.
private void CreateNewFlight()
{
string flightCode = ReadFlightCode();
//Create the new bidder
if (!string.IsNullOrEmpty(flightCode))
{
FlightWindow frm = new FlightWindow(Flightcode.Text);
frm.Show();
//Subscribe to the publisher's new bid and quit bid events
frm.NewStart += OnNewStartClick;
frm.NewChangeRoute += OnNewChangeRoute;
frm.OnNewLand += OnNewLand; <----Here is the error <-------
}
}
Cannot assign to 'OnNewLand' because it is a 'method group
My other window:
public event EventHandler<Start> NewStart;
public event EventHandler<ChangeRoute> NewChangeRoute;
public event EventHandler<Land> NewLand;
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Start startinfo = new Start(this.Title);
OnNewStart(startinfo); //Raise event
btnLand.IsEnabled = true;
Routetxt.IsEnabled = true;
changebtn.IsEnabled = true;
btnStart.IsEnabled = false;
}
private void changebtn_Click(object sender, RoutedEventArgs e)
{
ChangeRoute changeinfo = new ChangeRoute(this.Title, Routetxt.Text);
OnNewChangeRoute(changeinfo); //Raise event
}
private void btnLand_Click(object sender, RoutedEventArgs e)
{
Land landinfo = new Land(this.Title);
OnNewLand(landinfo); //Raise event
}
//Raise Event
public void OnNewStart(Start e)
{
if (NewStart != null)
NewStart(this, e);
}
public void OnNewChangeRoute(ChangeRoute e)
{
if (NewChangeRoute != null)
NewChangeRoute(this, e);
}
public void OnNewLand(Land e)
{
if (NewLand != null)
NewLand(this, e);
}
You need
frm.OnNewLand += NewLand;
instead of
frm.OnNewLand += OnNewLand;
You might be interested to know what does it mean by method group. Visit this so thread.
I want to move a shape in a window while user holds a key down.
I'm new to this so i tried this approach, but i can't change circle.RederTransform from my new thread, because it belongs to a different thread. How should it be done?
public partial class MainWindow : Window
{
private Matrix transformationMatrix = Matrix.Identity;
private Thread myThread = null;
private bool isGoing = false;
public MainWindow()
{
InitializeComponent();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
isGoing = true;
myThread = new Thread(HandleMyThread);
myThread.Start();
}
private void Window_KeyUp(object sender, KeyEventArgs e)
{
isGoing = false;
}
private void HandleMyThread(object obj)
{
while(isGoing)
{
transformationMatrix.Translate(10, 0);
circle.RenderTransform = new MatrixTransform(transformationMatrix);
Thread.Sleep(50);
}
}
}
In WPF you want to use the System.Windows.Threading.DispatcherTimer class for UI-thread safe timers.
Here is an example:
public partial class MainWindow : Window
{
private DispatcherTimer _timer;
public MainWindow()
{
InitializeComponent();
}
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(50);
_timer.Tick += timer_Tick;
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
_timer.Start();
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
_timer.Stop();
}
private void timer_Tick(object sender, EventArgs e)
{
transform.X += 2;
transform.Y += 2;
}
}
You might get away with doing it by just using an Invoke...but there are better ways to do what you want to do.
Firstly, creating a thread each time you handle the KeyDown is inefficient...and could lead to problems...because it may take a while to create and schedule the Thread...thus a delay in your "thing" moving.
In addition it's possible for you to get in a mess with having multiple threads staying in existence. For instance, say someone was repeatedly pressing and releasing the key....in that case it's possible for "old" threads to still keep running...because isGoing flag is true....in other words, there is poor synchronization.
private void HandleMyThread(object obj)
{
Action action = new Action( ()=>
{
transformationMatrix.Translate(10, 0);
circle.RenderTransform = new MatrixTransform(transformationMatrix);
};
while(isGoing)
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, action);
Thread.Sleep(50);
}
}