I developing a Xamarin application, and I communicating an external custom device. My problem is very strange, firstly the application starting, and connecting automatically to device, so everything is fine. When i suddenly remove the battery from the external device, the bluetooth connection is broken, and it's working fine to, but when I turn on the external device again, my Xamarin application connecting to it very well well, but the subscriptions not working anymore.
I debugged it, but not calling anymore. I think the unsubscribe/subscribe process is wrong.
...
if (ble.GetConnectionStatus())
{
Device.BeginInvokeOnMainThread(() =>
{
...
ble.Adapter.DeviceConnectionLost -= Adapter_DeviceConnectionLost;
ble.Adapter.DeviceConnectionLost += Adapter_DeviceConnectionLost;
ble.PropertyChanged -= Ble_PropertyChanged;
ble.PropertyChanged += Ble_PropertyChanged;
data.PropertyChanged -= data_PropertyChanged;
data.PropertyChanged += data_PropertyChanged;
...
});
...
So it's so strange, because first time this working, when starting the app, but when I call it after reconnect that same subscription not working. So if its wrong, then why working this at very first time?
I have no error, just not fire the functions again after resubscribe.
So as you see, I need to "refresh" the subscription. Is there another way to solve this problem?
If that "button to recreate everything" works, then I see two alternatives.
Option 1:
Have such a button, so that user can manually "fix" the situation.
PRO: Gives the user a solution that is guaranteed to work.
CON: Requires user intervention.
Option 2:
Have a periodic timer, that decides whether/when to forcibly "fix" the situation.
PRO: Automatically recovers.
CON: Risks losing data, if forces a recovery at the same time data is arriving.
In pseudo-code, option 2 might be something like this:
// pseudo-code
static Timer timer = ..start a timer that has an event every 10 seconds.
OnTimerElapsed:
if (!eventSeenRecently)
ForceReset();
eventSeenRecently = false;
..whereever you receive data..
if (..has data..)
eventSeenRecently = true;
The concept is that you keep track of whether data continues to be received. If the device stops sending you information (but you believe it should be), then you "ForceReset" - whatever is needed to get everything going again.
DeviceConnectionLost should also set some flag, that you use to ForceReset when the device "comes back".
// pseudo-code
DeviceConnectionLost:
resetNeeded = true;
OnTimerElapsed:
if (resetNeeded && ..test that device is available again..) {
ForceReset();
resetNeeded = false;
}
Perhaps this custom device has some option or info that can help.
For example, there might be a way to query some id or other info, so you can discover that the device is now "different", in a way that requires the reset. Then the timer does that query, and uses that info to decide to reset.
Related
I'm using zkemkeeper dll in a .net windows forms app.
This is my code
objCZKEM.OnConnected += ObjCZKEM_OnConnected;
objCZKEM.OnDisConnected += objCZKEM_OnDisConnected;
if (objCZKEM.Connect_Net(IPAdd, Port))
{
//65535, 32767
if (objCZKEM.RegEvent(1, 65535))
{
// [ Register your events here ]
// [ Go through the _IZKEMEvents_Event class for a complete list of events
objCZKEM.OnEnrollFinger += ObjCZKEM_OnEnrollFinger;
objCZKEM.OnFinger += ObjCZKEM_OnFinger;
objCZKEM.OnAttTransactionEx += zkemClient_OnAttTransactionEx;
objCZKEM.OnDoor += ObjCZKEM_OnDoor;
}
objCZKEM.RegEvent(1, 65535);
return true;
}
return false;
I can connect to the device get the logs etc.
OnConnected event is fired.
But no real-time event other than OnAttTransactionEx ever gets called. OnFinger and OnDoor don't work. To be honest I haven't registered a new finger so I don't know if OnEnrollFinger works.
I want to block some users from opening the door using some conditions in my own application. I don't know how I can achieve this. I thought I can use OnFinger event and block the user there. But I'm not sure if it is the way to do this.
Thanks in advance
In the latest models' firmware, real time event is disabled due to the business reasons for the cloud solutions from zk. You have to reply on "biometric web api" for getting the real time attendance to your server. If you want to develop only as a desktop application, then you have to poll for the the attendance logs.
For disabling the user from accessing the door, you need to ensure that the user is deleted from the biometric device as soon as you find him/her as ineligible
Context
I'm developing a traffic management app using C# (Xamarin Forms) which requires a constant feed of the user's location.
Plugin
I'm using the Geolocator plugin by James Montemagno and the PositionChanged event on the IGeolocator interface seems to be triggering twice when a position change occurs.
Device
I'm currently debugging on an Android Emulator on Visual Studio Enterprise v15.5.3
Steps to reproduce the behaviour
1) After instantiating the locator object:
IGeolocator locator = CrossGeolocator.Current
2) Some code for when the locator's PositionChanged is triggered:
locator.PositionChanged += (sender,e) => {
// Testing its frequency
System.Diagnostics.Debug.WriteLine("Position Changed Triggered.");
}
3) Start listening in an async Task function
locator.DesiredAccuracy = 100;
if(!locator.isListening)
await locator.StartListeningAsync(TimeSpan.FromMilliseconds(500), 1, true);
4) Send coordinates via the emulator
Expected Results
The output window should display one message saying "Position Changed Triggered".
Actual Results
The output window has two identical messages printed, saying: "Position Changed Triggered".
Why is this happening? and how can I make it so that the event is ONLY triggered/handled ONCE for every time the position is actually changed.
What I've tried so far
Googled the issue, not many identical situations found.
Saw an explanation here which makes me believe it's the emulator has something to do with it, although I found the solution a bit ambiguous and am not sure what they're referring to with "Live/Pin Mode"
Created a separate function and assigned the event to it, then removed it after calling my code. This does cause it to execute once, but it never executes again unless I reassign in. And if I do, sure enough the code will run for the second time, resulting in the same initial problem.
Tried setting a boolean to check if it has already run once, but realised not long after how that's illogical.
Tried to set a DateTime object to make sure no more than 1 event occurs in a given time frame; this was also no good.
Help would be appreciated. Thanks.
Please note that the location service might deliver a location event more than one time (more here).
Even if the location service is not delivering the location event more than one time, usage and/or implementation of the API (Geolocator plugin) might cause reception of the location event more than one time from the API.
In the app you might check the location event properties (accuracy, location timestamp, order of event received, etc.). Use the "best" location event with "best" meaning preferred accuracy, most recent timestamp, or the first received location event if timestamp and accuracy are equal.
I am making an application in which i want to execute some database queries just before system get shut down. I am using this code -
static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
e.Cancel = true;
MessageBox.Show("Shut down canceled");
}
I did execute this application and tried to shut down the system and this code captured the shut down event also but the problem is after showing message box it shows this screen also- [I can't post the image as i don't have 10 points.]
it shows the name of my application that stopped the system to get shut down and it also provide "Force Shut down button" , i dont want this screen to be displayed as user can forcefully shut down the system before completion of execution of my queries.
Need expert advices on this, thanks a lot in advance.
The Short Reliable Answer:
On any recent Windows version, you can try to cancel shutdown but Windows may decide to ignore you; this is sadly by design. If you absolutely have to finish operations before your process is terminated, the right place to do this is in the SessionEnded handler. If you have tasks that must complete before your process terminates, you must not return from your SessionEnded handler until all your work is done (so your queries, etc. have finished.)
So instead of (or as well as, if you prefer) handling SessionEnding, handle SessionEnded and do you work there:
static void SystemEvents_SessionEnded(object sender, SessionEndedEventArgs e)
{
WaitForQueriesToFinishOrSaveState(); // new code
}
How you implement that waiting will depend on your application; if you need to run queries afresh you may be able to do them therein, or you may need to Thread.Join() or otherwise wait for background tasks to complete; but it must be a blocking wait (so you need to not return from the function until you're done).
Since you can't absolutely stop shutdown, there's perhaps little point in attempting the cancellation in this case, so I'd recommend not setting e.Cancel in SessionEnding at all. On older Windows versions this was more meaningful, very much less so now unfortunately.
It's also recommended by the API docs not to do any significant work in SessionEnding (including message boxes), but to set any flags you need to return immediately and then do the work in SessionEnded. (Unproven aside: I'm suspicious that if you don't return quickly enough, this may hasten the appearance of the "programs are misbehaving, do you want to kill them" screen for the user, as Windows believes you're not playing nice any more.)
Behind the Scenes:
Setting e.Cancel indicates to Windows that you'd like the session not to end; but the user still gets a look in; and Windows may decide to ignore your request for any reason it feels pertinent. That's just the way the cookie crumbles. You may find hacks that work situationally, but there's no API or approach which is Microsoft-approved and therefore likely to work consistently now and in the future.
Under the covers, Windows is sending your process' windows a WM_QUERYENDSESSION message, which .NET receives for you and translates into the SessionEnding event) and will pass your cancellation (or lack of) back to Windows; returning TRUE if you don't cancel, FALSE if you do.
After this, Windows takes a look at all process' requests and depending on the cause of the shutdown and other factors may well still decide to go ahead despite such requests. It may also alert the user if processes are not cooperating and give them the option of killing the process.
Whether you handle WM_QUERYENDSESSION (SessionEnding) or not, you always get one last chance to clean up: you're sent a WM_ENDSESSION message (translated into SessionEnded). The tricky part is that you have to do all your vital tasks before all your SessionEnded handlers have returned!
Once Windows hears back from its WM_ENDSESSION (SessionEnded) call, all bets are off as far as your application's lifetime is concerned and Windows can terminate your process at any point.
Raymond Chen covered this quite expertly and quite recently.
http://blogs.msdn.com/b/oldnewthing/archive/2013/06/27/10429232.aspx
As a footnote, SystemEvents.SessionEnded is a convenience; if yo have a top level application window you can bypass it entirely and achieve the same via:
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x16) // WM_ENDSESSION
{
WaitForQueriesToFinishOrSaveState();
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
in shutdown command there's a switch for abort shutdown. you have to call this command by your c# code
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = false;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine(#"shutdown -a");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
I have a little problem with saving my state to localsettings. Everything is ok except the situation when someone close my application using alt + f4 and open it before 10 seconds elapsed(after 10 seconds application is in state suspending and data is saved). (Technology xaml/c#)
I save my data in event OnSuspending.
I load my data in event OnLaunched like this:
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated ||
args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser)
{
// save data
}
How to handle this situation ? I know i can save my state every time it is changed but i think it is not good idea in my application.
Thanks for help !
When you close and launch your application before 10 seconds elapsed another instance of it is created and the previous one does not run OnSuspending event (it is strange because it means that asynchronous operations like this event can end or never start without warning us). I think that this is annoying but why would your user do something like that? Most of the times the user "restart" your application because it crashed or he is stuck and can't go back to the main page. You should try to prevent those scenarios and such think rarely will happen.
However, this can also happen because the user forgot to do something and want to start the app again. To prevent lost user data I save the most important data whenever I get the chance and save the rest only OnSuspending method. You need to think about what data will upset your users when lost.
I think Microsoft should get a better way of saving application state. I searched a lot about this problem and didn't found an explanation so for now I will continue to do what I said above. I hope this question you made can help and clarify me about this, in my opinion, strange case.
onLaunched :
CoreWindow.GetForCurrentThread().Activated += App_Activated;
and event:
void App_Activated(CoreWindow sender, WindowActivatedEventArgs args)
{
if (args.WindowActivationState == CoreWindowActivationState.Deactivated)
{
//save Data
}
}
When you load data, remove:
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated || args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser)`.
It works !
I start the Windows On-Screen-Keyboard like that:
s_onScreenKeyboard = new Process();
s_onScreenKeyboard.StartInfo = new ProcessStartInfo("osk.exe");
s_onScreenKeyboard.EnableRaisingEvents = true;
s_onScreenKeyboard.Exited += new EventHandler(s_onScreenKeyboard_Exited);
s_onScreenKeyboard.Start();
This works fine, but when I try to stop it using the following code, it does not work, i.e. the OSK keeps running and the method returns false:
s_onScreenKeyboard.CloseMainWindow();
if (!s_onScreenKeyboard.HasExited)
{
if (!s_onScreenKeyboard.WaitForExit(1000))
{
s_onScreenKeyboard.Close();
//s_onScreenKeyboard.Kill();
}
}
When uncommenting s_onScreenKeyboard.Kill(); it is closed, but the problem is that osk.exe obviously uses another process called "msswchx.exe" which is not closed if I simply kill the OSK process. This way, I would end up with hundreds of these processes which is not what I want.
Another strange thing is that the CloseMainWindow() call worked at some time, but then it suddenly did not work anymore, and I do not remember what has changed.
Any ideas?
EDIT: I have found a solution myself. Please see my answer for details.
Background:
I am implementing an On-Screen-Keyboard for my application because it should work with a touchscreen. It is important that the keyboard layout matches the layout which is configured in Windows since the application will be shipped to many different countries. Therefore, instead of implementing a custom keyboard control with approx. 537 keyboard layouts (exaggerating a little here...), I wanted to utilize the Windows built-in On-Screen-Keyboard which adapts to the selected keyboard layout automatically, saving a lot of work for me.
I have found the/a solution myself:
When I successfully retrieve the MainWindowHandle after the process has been started, the call to CloseMainWindow() is also successful later on. I do not understand the reason for this, but the important thing is: it works!
BTW, for others having the same problem: The MainWindowHandle is not available immediately after starting the process. Obviously, it takes some milliseconds until the MainWindow is started which is why I use the following code to retrieve the handle:
DateTime start = DateTime.Now;
IntPtr handle = IntPtr.Zero;
while (handle == IntPtr.Zero && DateTime.Now - start <= TimeSpan.FromSeconds(2))
{
try
{
// sleep a while to allow the MainWindow to open...
System.Threading.Thread.Sleep(50);
handle = s_onScreenKeyboard.MainWindowHandle;
}
catch (Exception) { }
}
In this code I continuously get the MainWindowHandle every ~50ms as long as it is still equal to IntPtr.Zero. If the handle could not be retrieved after 2 seconds, I quit the loop to avoid an endless loop in case of error.
You need to wait untill the process finishes initialization, run
Process.WaitForInputIdle Method in order to do that.