I was wondering if anyone could offer some advice. I need to automate a process within my program that when fingerprint has been captured, it automatically goes to the next page through calling ShowNext() in the wizard.
public partial class AddFingerprintsPage : Neurotec.Samples.WizardPage
...
#region Scanner // Fingerprint Scanner
public void timer1_Tick(object sender, EventArgs e)
{
Timer timer1 = new Timer();
timer1.Interval = 1000;
timer1.start() //
{
Form2 f2 = new Form2();
f2.Show(); // Display Form2 which asks user to present finger..
}
if (capturing..)
{
blah blah capture finger..
timer1.stop()
}
}
....
public partial class WizardForm : Form
....
public void ShowNext() // In the wizard form, go to the next page
{
ShowPage(_currentPage + 1, false);
}
I am not sure what is the best away around this. I have tried making an if statement so when timer1.stop occurs in fingerprints then I call it in WizardForm and go to next page. But I am pretty sure I am not calling it correctly and even if I had I still have this error 'an object is required for the non-static field, method of property 'NeurotechSamples.AddFingerprintsPage.timer1'
public void ShowNext()
{
if(Neurotec.Samples.Fingers.AddFingerprintsPage.timer1.stop()) // Not sure what to call here?
ShowPage(_currentPage + 1, false);
}
Any help would be appreciated!
On the AddFingerprintsPage, add a static bool and call it "Stopped" and set the value to true when the timer stops:
public static bool Stopped = false;
if (capturing..)
{
blah blah capture finger..
timer1.stop()
Stopped = true;
}
Then you can say:
public void ShowNext()
{
if(Neurotec.Samples.Fingers.AddFingerprintsPage.Stopped)
{
ShowPage(_currentPage + 1, false);
}
}
The error that you are getting is saying that you need to create a new instance of Neurotec.Samples.Fingers.AddFingerprintsPage in order to reference timer1 because it is not static.
Related
I come from embedded C programming and I don't absolutely know anything about oop, task, threads, ecc..
I'm figuring out the basics concepts of C# and oop and wanted to try coding a simple stopwatch.
Goal: Toggle the stopwatch state with a button and show the value inside the button itself.
So far I've come to this:
namespace Cronometro
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MyTimerClass
{
private DateTime TimeValue;
private System.Timers.Timer TimerObj;
private const int TimeInterval = 1;
public MyTimerClass()
{
TimeValue new DateTime(0, 0, 0, 0, 0, 0, 0, DateTimeKind.Local);
TimerObj = new System.Timers.Timer(TimeInterval);
TimerObj.AutoReset = true;
TimerObj.Elapsed += TimerObj_Elapsed;
}
private void TimerObj_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeValue = TimeValue.AddMilliseconds((double)TimeInterval);
}
public void Start()
{
TimerObj.Start();
}
public void Stop()
{
TimerObj.Stop();
}
}
}
Come to this point, I just wanted to print the value with Button.Content but seems like I cannot use it outside of the MainWindow class.
What should I do? I started thinking about creating a task inside the main class and wait for the timer event to print the value but I know nothing about threads and tasks.
It's unclear exactly what you mean, as at the moment you can't use it in the MainWindow class at all. Just expose the value via a public function, and you can fetch the instance's value anywhere you want.
namespace Cronometro
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var x = new MyTimerClass(); // <<<
x.Start(); // <<<
var timeValue = x.GetTimeValue(); // <<<
}
}
public class MyTimerClass
{
private DateTime TimeValue;
private System.Timers.Timer TimerObj;
private const int TimeInterval = 1;
public MyTimerClass()
{
TimeValue new DateTime(0, 0, 0, 0, 0, 0, 0, DateTimeKind.Local);
TimerObj = new System.Timers.Timer(TimeInterval);
TimerObj.AutoReset = true;
TimerObj.Elapsed += TimerObj_Elapsed;
}
private void TimerObj_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeValue = TimeValue.AddMilliseconds((double)TimeInterval);
}
public DateTime GetTimeValue() // <<<
{ // <<<
return TimeValue; // <<<
} // <<<
public void Start()
{
TimerObj.Start();
}
public void Stop()
{
TimerObj.Stop();
}
}
First, you don't have to write your own Stopwatch class. DotNet has its own:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=netframework-4.8
Second, try to understand async/await pattern:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
So, you can do something like this:
https://wouterdekort.com/2013/10/01/async-and-await-and-the-ui-thread/
One way you could populate the button text is you create an event in the MyTimerClass class, and attach a listener delegate to it from inside the MainWindow class.
Then, fire the event in TimerObj_Elapsed in MyTimerClass, so that the event handler in MainWindow will be called, and you will have a chance to populate the button.
However, there is something other than "practicing class" you have to deal with. Because you are using a thread pool timer, so the Elapsed event handler of the timer is invoked from a worker thread. In a GUI app, only the main / UI thread can interactive with controls. So chances are, you will get an exception when trying to set Button.Text. You will need to marshal the set action to the UI thread.
Frankly, if you are practicing writing classes in C#, I'd recommend you using a Console App to start with rather than a GUI app. It is probably not a good idea if people throwing out too many concepts on the table that you don't know at the same time.
Say I have a common class that performs some time-consuming step (eg. saving stuff to USB). I'd like to be able to call that code from multiple forms and receive feedback whenever a step is completed. How does the common class know to whom to send feedback to? The code below describes the situation:
// ### Common class frmCommon ###
// Parent form (when feedback on some slow operation is required)
private static Form m_frmParent = null;
// ...
public static void SetParentForm(Form frmParent)
{
// When some time consuming process takes place (such as saving to USB), setting the
// parent form allows feedback to be given to the user (eg. as a progress bar)
m_frmParent = frmParent;
}
public static void DoSomething()
{
for (int nStep = 0; nStep < 100; nStep++)
{
// Tell the parent form how many product sets (groups of 20) there are to read
if (m_frmParent != null)
{
// How to decide whether to call form 1 or form 2?
((frmForm1)m_frmParent).SendFeedback(nStep);
((frmForm2)m_frmParent).SendFeedback(nStep);
}
// Perform the time-consuming step...
SlowStep(nStep);
}
}
// ### FORM 1 frmForm1 ###
private void SomeEventForm1(int nStep)
{
frmCommon.SetParentForm(this);
frmCommon.DoSomething();
frmCommon.SetParentForm(null);
}
public void SendFeedback(int nStep)
{
// Do something like update a progress bar on form 1
Application.DoEvents();
}
// ### FORM 2 frmForm2 ###
private void SomeEventForm2(int nStep)
{
frmCommon.SetParentForm(this);
frmCommon.DoSomething();
frmCommon.SetParentForm(null);
}
public void SendFeedback(int nStep)
{
// Do something like update a progress bar on form 2
Application.DoEvents();
}
Aiming for .NET 2.0 if that makes a difference.
I'd rather use an event:
public class SlowProcess {
...
// Simplest, not thread safe
public static event EventHandler<int> StepChanged;
public static void DoSomething() {
for (int nStep = 0; nStep < 100; nStep++) {
if (null != StepChanged)
StepChanged(null, nStep);
SlowStep(nStep);
}
}
}
...
public partial class MyEventForm: Form {
...
private void onStepChange(Object sender, int nStep) {
//TODO: update form here after receiving a feedback
}
private void TraceSlowProcess() {
// feedback is required
SlowProcess.StepChanged += onStepChange;
try {
SlowProcess.DoSomething();
}
finally {
// No need of feedback
SlowProcess.StepChanged -= onStepChange;
}
}
}
The calling code will have to provide a delegate to that class. When the class is done with the time consuming process, it will call that delegate to inform the calling code that it finished. Look here for a good tutorial on how to do this.
1 - If SendFeedback is a function you implemented in both forms, and they do the same, consider creating a single static method in a static class to extend the Form:
public static class FormExtender
{
public static void SendFeedback(this Form frm, int nStep)
{
//do what must be done
//you can call this anyhere using, for instance: m_frmParent.SendFeedback(nStep)
//when you call it like that, m_frmParent will be given to this function as the argument frm
}
}
2 - But if the methods are different in both forms, I suggest you create an interface:
interface IFormWithFeedback
{
void SendFeedback(int nStep);
}
Then form1 and form2 should implement this (just add , IFormWithFeedBack where your forms are declared):
public class frmForm1 : Form, IFormWithFeedback
public class frmForm2 : Form, IFormWithFeedback
And your parent form inside that class should be an IFormWithFeedback instead of a form:
private static IFormWithFeedback m_frmParent = null;
Both options (extension method or interface) would allow you to call SendFeedback direclty from m_frmParent without casting it.
I want to have a timer in my windows phone 8 app, that´s counting/running independent of current shown page.
It should connect to server - when possible in a UI independet task/thread - and store data in a global object/list.
The Independence from current shown page is my point.
I tried following in App.xaml.cs:
public partial class App : Application
{
// creating timer instance
DispatcherTimer gAppTimer = new DispatcherTimer();
// timer interval specified as 1 minute
gAppTimer.Interval = TimeSpan.FromSeconds(60);
// Sub-routine OnTimerTick that will be called at specified intervall
gAppTimer.Tick += OnTimerTick;
// starting the timer
gAppTimer.Start();
public void OnTimerTick(Object sender, EventArgs args)
{
// text box property is set to current system date.
// ToString() converts the datetime value into text
MessageBox.Show("TIMER fired");
}
:
:
But this doesn´t work. Than I tried just declaring the object in App.xaml.cs:
public partial class App : Application
{
// creating timer instance
DispatcherTimer gAppTimer = new DispatcherTimer();
public void OnTimerTick(Object sender, EventArgs args)
{
// text box property is set to current system date.
// ToString() converts the datetime value into text
MessageBox.Show("TIMER fired");
}
:
:
And on my startpage.xaml.cs:
// timer interval specified as 1 minute
App.gAppTimer.Interval = TimeSpan.FromSeconds(60);
// Sub-routine OnTimerTick that will be called at specified intervall
App.gAppTimer.Tick += OnTimerTick;
// starting the timer
App.gAppTimer.Start();
But this doesn´t work, too.
Any ideas how to handle my Problem? What I don´t want to use is a Background Task, because it runs only every 30 minutes. My solution should only run, if the app is "active" (in foreground).
That's normally done using a static or singleton class. Both will be global and you'll have access to them from every page.
Also, the DispatcherTimer invokes it's TimerTick method on the UI thread. If you don't need to be in the UI thread, you should use a System.Threading.Timer, which invokes a method in a background thread.
Here's an example:
public static class SomeManager {
private static Timer gAppTimer;
private static object lockObject = new object();
public static void StartTimer() {
if (gAppTimer == null) {
lock (lockObject) {
if (gAppTimer == null) {
gAppTimer = new Timer(OnTimerTick, null, 60 * 1000, 60 * 1000);
}
}
}
}
public static void StopTimer() {
if (gAppTimer != null) {
lock (lockObject) {
if (gAppTimer != null) {
gAppTimer.Change(Timeout.Infinite, Timeout.Infinite);
gAppTimer = null;
}
}
}
}
private static void OnTimerTick(object state) {
Action();
}
public static void Action() {
// Do what you need to do
}
}
Just call SomeManager.StartTimer() from your first page or from App.xaml.cs and the timer will start.
Update
I updated the code a little:
Renamed the Initialize method to StartTimer.
Added StopTimer method which stops the timer. You can then start it again by calling SomeManager.StartTimer.
Added Action method which is the one actually donig the work. You can invoke it from anywhere, anytime.
Note: the the timer will call this method in a background thread and you should do the same using something like Task.Run(() => SomeManager.Action());
Added a lock to ensure that the Start/Stop methods will not throw exceptions if invoked from multiple threads at the same time.
I'm not sure how you have arranged your code, but as I've tried:
public partial class App : Application
{
public static PhoneApplicationFrame RootFrame { get; private set; }
public DispatcherTimer gAppTimer = new DispatcherTimer();
public void OnTimerTick(Object sender, EventArgs args)
{
MessageBox.Show("TIMER fired");
}
public App()
{
gAppTimer.Interval = TimeSpan.FromSeconds(2);
// Sub-routine OnTimerTick that will be called at specified intervall
gAppTimer.Tick += OnTimerTick;
// starting the timer
gAppTimer.Start();
// rest of the code
the above code works. MessageBox shows every 2 seconds, if you had declared your DispatcherTimer as public, then you will be able to access it like this:
(App.Current as App).gAppTimer.Stop();
Note also that depending on what you want to achieve you may also use System.Threading.Timer.
On the other hand you may also think of using public static DispatcherTimer somewhere.
My application has a restricted access. I have a user/password box in a small dialog, and when logged-in, I'm loading a very big form with a tons of controls and several big grids. The whole InitializeComponent() take almost 10 secs to load without any data.
The issue is : how I could pre-run the Form constructor() while users are filling the two login fields ? If user is very slow and need >10 secs to complete authentification, it will be as quick as a wink to show application.
I think it is possible because it is two seperates top level windows, but I have no idea how to implement it. BackgroundWorker, new Thread, ... ? Any clue ?
SOLUTION :
Following Eamonn McEvoy's example, I added some fixes about my prerequesites : I wanted to show only login dialog, and if logged successful, I show the big form.
[STAThread]
static void Main()
{
Launcher context = new Launcher();
Application.Run(context);
}
public class Launcher : ApplicationContext
{
private BigForm _bigForm;
private Thread _loginThread;
private SynchronizeLogin _sharedLogin;
public class SynchronizeLogin
{
private bool _waited = false;
public bool IsInitialized
{
get // loginform should wait before closing until return true
{
lock (this)
{
return _waited;
}
}
set // must be set when bigform is initialized
{
lock (this)
{
_waited = value;
}
}
}
private DialogResult _logged = DialogResult.None;
public DialogResult loginResult
{
get // wait until loginform close
{
lock (this)
{
if (_logged != DialogResult.None)
return _logged;
else
{
Monitor.Wait(this);
return _logged;
}
}
}
set // set from loginform when closing
{
lock (this)
{
_logged = value;
Monitor.Pulse(this);
}
}
}
}
public Launcher()
{
// sync obj between forms
_sharedLogin = new SynchronizeLogin();
_loginThread = new Thread(new ThreadStart(LaunchLogin));
_loginThread.Start();
// first form
_bigForm= new BigForm(_sharedLogin);
_bigForm.Closed += new EventHandler(OnFormClosed);
// notify login thread that the main one is ready
// from now, the login form should be near closing
_sharedLogin.IsInitialized = true;
WaitLogon();
}
private void WaitLogon()
{
if (_sharedLogin.loginResult == DialogResult.OK)
{
_bigForm.LoginSuccessful(); // read and use auth session
_bigForm.Show();
}
else
{
// escape on user login form
// (other exit calls are not working in ctor)
Environment.Exit(42);
}
}
private void LaunchLogin()
{
// ask user
LoginDialog _loginForm = new LoginDialog (_sharedLogin);
_sharedLogin.loginResult = _loginForm.ShowDialog();
// userlogin form closed
// end only current thread
Application.ExitThread();
}
private void OnFormClosed(object sender, EventArgs e)
{
// big form closed
// end ApplicationContext globally
base.ExitThread();
}
}
You could create your login window in a new thread from your main windows constructor
using System.Threading;
private AuthSession _authSession;
public MainWindowConstructor()
{
Thread loginThread = new Thread(new ThreadStart(Login());
loginThread.Start();
//Continue initializing
}
private void Login()
{
LoginWindow loginWindow = new LoginWindow();
_authSession = loginWindow.GetAuthSession();
loginWindow.Close();
}
Is it possible to close a form while the constructor is executing (or simply to stop it showing at this stage)?
I have the following code:
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Close();
}
}
}
Which throws an ObjectDisposedException in Main(), here:
static void Main()
{
...
// Following line errors
Application.Run(new MyForm());
}
I’ve tried checking the result of MyForm like this:
static void Main()
{
...
MyForm frm = new MyForm();
if (frm != null)
{
// Following line errors
Application.Run(frm);
}
}
But that doesn’t seem to help. Can anyone tell me a way around this, please? Maybe a way to check the form to see if it still exists?
Calling Close from the constructor of the Form is not possible, as it will call Dispose on a Form that has not yet been created. To close the Form after construction, assign an anonymous event handler to the Load event that closes your Form before it is displayed for the first time:
public partial class MyForm : Form
{
public MyForm()
{
if (ShouldClose())
{
Load += (s, e) => Close();
return;
}
// ...
}
// ...
}
The only thing you could do it set a flag to close it in the constructor, and then closing it in the Shown event. Of course, if you're doing that, it makes sense to move the code to determine whether it should be closed there in the first place.
The following works well:
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Shown += new EventHandler(MyForm_CloseOnStart);
}
}
private void MyForm_CloseOnStart(object sender, EventArgs e)
{
this.Close();
}
}
When you call Close() on a form, internally it is disposing of the form and releasing any managed resources. When you do this:
Application.Run(new MyForm());
You'll likely get an ObjectDisposedException. What you need to do is set the Form's visibility through a property:
Application.Run(new MyForm() { Visible = false });
Just make sure you remove the call to Close() in the constructor, or even move the property assignment there too.
Can you make MyFunc static? and then do something like:
static void Main()
{
...
if (MyForm.MyFunc())
{
Application.Run(new MyForm());
}
}
this would essentially give you the same control over whether the form is going to be constructed or not?
I found adding a handler to the 'Load' event is better as this way the dialog is never displayed at all. With the 'Shown' event you might briefly see the dialog open and then close which may be confusing:
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Load += MyForm_CloseOnStart;
}
}
private void MyForm_CloseOnStart(object sender, EventArgs e)
{
this.Close();
}
}
I think it is not wise to close a form in the constructor. If you do this, users of your form wouldn't know whether to ShowDialog or not.
The following code would be quite normal use:
// in the parent form:
public void ShowMyForm()
{
MyForm form = new MyForm();
form.propertyA = ...;
from.propertyB = ...;
DialogResult dlgResult = form.ShowDialog(this);
ProcessDialogResult(dlgResult);
}
If you decided in the constructor whether the Form ought to be shown, you would have to add code after construction to decide whether to call ShowDialog or not and whether to Process the dialog result.
Furthermore, are you sure that changing the properties will never influence whether the form is to be shown or not? Also after future changes?
During construction the form is not shown / opened yet. So I'm afraid Close() doesn't do what you expect.
The neat method is to do the checks that you wanted to do in the constructor in the Form_Load. Add an event handler for form-load and do your checks in the event handler. Use the property DialogResult to indicate that you decided not to show the form.
private void FormMain_Load (object sender, EventArgs e)
{
if (FormShouldNotLoad())
{
this.DialogResult = System.Windows.Forms.DialogResult.Abort;
Close();
// Warning, this does not work, see below, (but we're almost there!)
}
}
The user of the code could check the result of the dialog:
// in the parent form:
public void ShowMyForm()
{
MyForm form = new MyForm();
form.propertyA = ...;
from.propertyB = ...;
DialogResult dlgResult = form.ShowDialog(this);
switch (dlgResult)
{
case System.Windows.Forms.DialogResult.Abort:
ProcessFormNotLoaded();
break;
case System.Windows.Forms.DialogResult.OK:
ProcessFormOk();
break;
// etc.
}
}
However, calling Close() in the event handler for form-load won't work, because Close() can only be called properly after Load is completed.
Therefore, instead of calling Close(), you should BeginInvoke the Close() function, so the Close function will be called after loading is done:
private void FormMain_Load (object sender, EventArgs e)
{
if (FormShouldNotLoad())
{
this.DialogResult = System.Windows.Forms.DialogResult.Abort;
// invoke the Close function after Load completed
this.BeginInvoke(new MethodInvoker( () => this.CancelLoading())
}
}
Environment.Exit(...) is working for me (without window flickering):
public partial class MyForm : Form
{
public MyForm()
{
if (weShouldClose)
{
Environment.Exit(0);
}
}
}
If you want your window to never be seen(no flickering windows that open for an instant and then disappear):
public new void Show()
{
if (MyFunc())
base.Show();
else
; // dispose or whatever
}
Though Show(...) has 2 overloads and ShowDialog(...) has 2 too.
Doesn't work for the main form that is opened via Application.Run(). But who would do that anyways? Except there is also a way to open main form without using Application.Run().