Silverlight Global Mouse Down Event Handler - c#

I am desperately trying to implement a "Session Inactivity Timeout" for an IT security policy.
sss
However, my inactivity reset logic isn't firing. What am I doing wrong? I can't attach a breakpoint due to Visual Studio crashing on attaching to Silverlight binary. I am wondering if the problem is something very subtle, such as at the time the App constructor is called, there is no "current RootVisual" yet. Tagging with #WPF as well since #Silverlight is dead/obsolescent. Sample code below.
namespace TestApp
{
public partial class App : Application
{
System.Windows.Threading.DispatcherTimer sessionTimer = new System.Windows.Threading.DispatcherTimer();
public App()
{
ResetSessionTimer();
this.RootVisual.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(rootVisual_MouseLeftButtonDown), true);
//this.RootVisual.MouseLeftButtonDown += rootVisual_MouseLeftButtonDown;
InitializeComponent();
}
private void ResetSessionTimer()
{
sessionTimer.Stop();
sessionTimer.Tick -= sessionTimer_Tick;
sessionTimer = new System.Windows.Threading.DispatcherTimer();
sessionTimer.Interval = TimeSpan.FromMinutes(1);
sessionTimer.Tick += sessionTimer_Tick;
sessionTimer.Start();
}
private void sessionTimer_Tick(object sender, EventArgs e)
{
System.Windows.Browser.HtmlPage.Document.GetElementById("LogoutButton").Invoke("click", null);
}
private void rootVisual_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// added this alert to see if code is even firing.
System.Windows.Browser.HtmlPage.Window.Invoke("alert", "hello, world");
ResetSessionTimer();
e.Handled = false;
}
}
}

I figured this out - somewhere in the code, the previous developer was overriding the this.RootVisual element with a new MainPage() in order to enable their homegrown dependency injection / MVVM architecture. I moved the logic from the App() constructor to right after this assignment operator, and it works like magic.

Related

Windows phone 8.1 universal app DataTransferManager UI not showing

In my windows phone 8.1 universal app project I am trying to make a share option.
But when I click on the button (ShareCommand) the Share UI is not showing up, I have tried this in the emulator and on a device.
The event is correctly wired up since the DataRequested event gets called, but after this event there is no Share UI showing.
Here is the code I use in my ViewModel (using prism framework).
private DataTransferManager _dataTransferManager;
private DelegateCommand _shareCommand;
// Share button
public DelegateCommand ShareCommand
{
get
{
return _shareCommand ?? (_shareCommand = new DelegateCommand(() =>
{
DataTransferManager.ShowShareUI();
}));
}
}
public override async void OnNavigatedTo(object navigationParameter, NavigationMode navigationMode, Dictionary<string, object> viewModelState)
{
base.OnNavigatedTo(navigationParameter, navigationMode, viewModelState);
// get data transfer manager and register events
_dataTransferManager = DataTransferManager.GetForCurrentView();
_dataTransferManager.DataRequested += DataTransferMangerDataRequested;
_dataTransferManager.TargetApplicationChosen += DataTransferMangerTargetApplicationChosen;
}
public override void OnNavigatedFrom(Dictionary<string, object> viewModelState, bool suspending)
{
base.OnNavigatedFrom(viewModelState, suspending);
// clean up events
_dataTransferManager.DataRequested -= DataTransferMangerDataRequested;
_dataTransferManager.TargetApplicationChosen -= DataTransferMangerTargetApplicationChosen;
}
private void DataTransferMangerTargetApplicationChosen(DataTransferManager sender, TargetApplicationChosenEventArgs args)
{
}
private void DataTransferMangerDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
var request = args.Request;
var deferral = request.GetDeferral();
request.Data.Properties.Title = "title test";
request.Data.Properties.Description = "description test";
request.Data.SetText("test hello");
request.Data.SetUri(new Uri("https://www.google.com"));
request.FailWithDisplayText("fail");
deferral.Complete();
}
I have tried setting different properties in the DataRequested event but still nothing.
Does anyone know what it could be? Do I need to set some permissions?
Edit:
Ok, weird I tried this in a new solution with only this code and it is working fine. But no idea why its not working in my current solution.
Ok I found out what was causing the problem.
I had to remove this, since this will cancel the operation. (I thought this will show if it failed for some reason and not cancel directly).
request.FailWithDisplayText("fail");

Destructor vs App.Current.Exit vs All other exit handlers

Im having an issue where i need to get my Classes to run a piece of code on exit.
Basically the code writes the Property's and Parameters to an XML file so they can be sent to the programmer to replicate the same settings as the client.
so i have created code like this on each of my classes.
~WorkspaceViewModel()
{
this.Save("Workspace");
}
my problem is that i cannot find a handler that will run before this destructor.
i have tried the following
//App.Current.Exit += new System.Windows.ExitEventHandler(ProgramExit);
//AppDomain.CurrentDomain.ProcessExit += new EventHandler(ProgramExit);
//App.Current.MainWindow.Closed += new EventHandler(ProgramExit);
//App.Current.Windows[0].Closed += new EventHandler(ProgramExit);
//AppDomain.CurrentDomain.DomainUnload += new EventHandler(ProgramExit);
//App.Current.MainWindow.Unloaded += new System.Windows.RoutedEventHandler(ProgramExit);
//System.Windows.Forms.Application.ApplicationExit += new EventHandler(ProgramExit);
//System.Windows.Application.Current.Exit += new System.Windows.ExitEventHandler(ProgramExit);
And saw something online about modifying the App class so i did this.
public partial class App : System.Windows.Application
{
public void OnExit()
{
this.OnExit();
}
public void App_Exit(Object sender, System.Windows.ExitEventArgs Args)
{
//Somelogic here
}
public App()
{
this.Exit += new System.Windows.ExitEventHandler(App_Exit);
}
}
could someone please help.
Are you using Windows Forms? If so, you can use the Closing event of the form. More reading: Form.Closing Event
Definition:
Occurs when the form is closing.
Example:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if(MessageBox.Show("Do you want to exit?", "Your app title", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
// cancel the closing
}
//otherwise the application will exit
}
You don't really need the if-statement, you can just call the Save method in this event and let the application exit afterwards.
You could do it this way (pseudocode)
Init();
window.Show();
Deinit();
You explicitly run initializers on application start and deinitiliazer on exit.
And in WPF it's done by using Application events, overrides or by a trick (setting Page build action for App.xml). In your implementation, you can't have constructor declared, because it's already generated (file App.g.i.cs). You can use application startup event though or simply set events in xaml.
As it turns out. all i needed to do was create a destructor on the App Class like this
public partial class App : Application
{
~App()
{
Administration.Model.DataBaseModel.GlobalCatalogue.ToFile();
}
}
Not really sure this is the best approach tho
Im still open to better ideas however.. thank you all.

MonoTouch memory issue with Threading / Timers

I am having an issue with MonoTouch where UIViewControllers are remaining in-memory forever, even after they have been popped from the navigation stack.
I have a UINavigationController which contains a UIViewController with a button. Clicking the button pushes a custom UIViewController called ThreadingViewController onto the navigation stack.
The ThreadingViewController uses a NSTimer.CreateRepeatingScheduledTimer and a Thread to update the text of a label every one second.
When the user clicks "back" to pop back to the root view, the Mono Profiler says that my ThreadingViewController still exists in memory. The Profiler tells me it has something to do with NSAction and/or ThreadStart which has a reference to the ThreadingViewController, keeping it alive. I can see this by checking the "inverse references" checkbox in the profiler.
This means that if the user clicks backwards and forwards 100 times between the root ViewController and the custom ThreadingViewController, there will be 100 instances of this ViewController in memory. It isn't being garbage collected.
In ViewDidDisappear I have tried aborting the thread, setting it to null, to no avail.
What do I need to do to get this ThreadingViewController to be properly cleaned up / GC'ed by MonoTouch?
Here is the full (C# only) source code to reproduce the problem:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Threading;
namespace MemoryTests
{
[Register("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
private UIWindow window;
private UINavigationController rootNavigationController;
private RootScreen rootScreen;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
rootScreen = new RootScreen();
rootNavigationController = new UINavigationController(rootScreen);
window.RootViewController = rootNavigationController;
window.MakeKeyAndVisible();
return true;
}
}
public class RootScreen : UIViewController
{
private UIButton button;
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.Title = "Root Screen";
// Add a button
button = new UIButton(UIButtonType.RoundedRect);
button.SetTitle("Click me", UIControlState.Normal);
button.Frame = new RectangleF(100, 100, 120, 44);
this.View.Add(button);
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
button.TouchUpInside += PushThreadingViewController;
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
button.TouchUpInside -= PushThreadingViewController;
}
private void PushThreadingViewController(object sender, EventArgs e)
{
var threadingViewController = new ThreadingViewController();
NavigationController.PushViewController(threadingViewController, true);
}
}
public class ThreadingViewController : UIViewController
{
private UILabel label;
private NSTimer timer;
private int counter;
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.Title = "Threading Screen";
// Add a label
label = new UILabel();
label.Frame = new RectangleF(0f, 200f, 320f, 44f);
label.Text = "Count: 0";
this.View.Add(label);
// Start a timer
var timerThread = new Thread(StartTimer as ThreadStart);
timerThread.Start();
}
public override void ViewDidDisappear (bool animated)
{
base.ViewDidDisappear(animated);
timer.Dispose();
timer = null;
// Do I need to clean up more Threading things here?
}
[Export("StartTimer")]
private void StartTimer()
{
using (var pool = new NSAutoreleasePool())
{
timer = NSTimer.CreateRepeatingScheduledTimer(1d, TimerTicked);
NSRunLoop.Current.Run();
}
}
private void TimerTicked()
{
InvokeOnMainThread(() => {
label.Text = "Count: " + counter;
counter++;
});
}
}
}
Here is a screenshot of the profiler telling me that we have 3 instances of ThreadingViewController in memory:
Cheers.
I think the problem is here:
timer.Dispose();
Try changing it to:
timer.Invalidate();
NSTimer is the only thing here that uses an NSAction.
Also, I don't think this is very helpful:
var timerThread = new Thread(StartTimer as ThreadStart);
timerThread.Start();
Reasons:
It's not a background thread. Not sure how foreground .NET threads behave on iOS. My guess is, it never finishes.
You don't need to have a separate thread live all the time, within from you are starting the NSTimer. NSTimers are light, bulletproof and provide all the options you need. They work great even if you are starting them on the UI thread.
(Please ignore #2 above if you have another reason you are doing it this way, which is not directly visible from your code. But, nothing else comes to mind).
PS: I haven't tested your code above. But I'm 100% sure that you must Invalidate() NSTimers so that they stop running, when you no longer need them.
Anytime you connect a click handler such as:
button.TouchUpInside += PushThreadingViewController;
You must also disconnect it. I would suggest moving the line of code above to the ViewDidAppear override, and adding the line of code below to the ViewDidDisappear override:
button.TouchUpInside -= PushThreadingViewController;
I would also recommend that you check to see if threadingViewController is null and only creating a new instance if it is, before pushing it onto the navigation stack. That way it will use the same one each time if it hasn't been garbage collected yet.
Be careful with ViewDidDisappear. This method may called at any time your View-Controller yields control to another View-Controller (calling PresentViewController, invoking the sharing UI, display an iAd etc). If you only want to react when your View-Controller is removed from the navigation stack, I'd recommend this:
public override void DidMoveToParentViewController(UIViewController parent)
{
base.DidMoveToParentViewController(parent);
if(parent == null)
Cleanup();
}
Try invoking ReleaseOutlets() (generated from the Xamarin Studio XIB processor) from within your Cleanup() method in addition to unwiring the touch event handler improves the situation.

How to avoid copy/paste many event handlers

My application cannot access a specific menu item unless some condition is true (DataRepository.IsAllDataLoaded). I came up with this code, which works great. It checks for the condition first. If it is not ready, it calls a timer, which waits some milliseconds and call the same method again. The Timer needs an ElapsedEventHandler.
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
if (!DataRepository.IsAllDataLoaded)
{
WaitForDataLoading(FirstTimedEvent);
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
}
private void FirstTimedEvent(object source, ElapsedEventArgs e)
{
FirstMenuItem_Click(null, null);
}
private static void WaitForDataLoading(ElapsedEventHandler timerEvent)
{
Timer t = new Timer();
t.Interval = 0.2;
t.AutoReset = false;
t.Elapsed += new ElapsedEventHandler(timerEvent);
t.Start();
}
Initially, the FirstMenuItem_Click was the only method. I had to add FirstTimedEvent handler for my timer. Is there a way to avoid creating that ElapsedEventHandler? Can I create it inline in my FirstMenuItem_Click method?
I now have to use that same pattern for many other Item_Click methods. I wish I don't have to create a ElapsedEventHandler for each Item_Click method.
Use an anonymous lambda expression:
WaitForDataLoading((s,e) => FirstMenuItem_Click(null, null));
You appear to be using WPF, based on your use of the Dispatcher class. That being the case, there are nicer means for you to control the access to your UI.
Two of these are:
bind your menu's Enabled property to ViewModel class, which would have a property to indicate whether the menu should be available. When your long-running job is complete, set the property to true and the menu will be enabled.
use an ICommand to drive the behaviour of your menu. The command's CanExecute return false while your long-running job is active, which will cause the menu to automatically be disabled until the job is complete.
It's worth noting that this will subtly change the behaviour of your menu - but not, I think, in a bad way. Your current code will wait for the job to complete before showing the dialog - but there's nothing to stop the user clicking the menu again in the meantime. These multiple clicks will each wait for the job to complete, and each display their own dialog when the job completes. In a trivial case this might mean that I see multiple dialogs appear; in a severe case the multiple timers that you're creating might badly affect the performance of the application.
Either of the methods suggested above would prevent the menu from being clicked while the job is running, which is not quite your current behaviour but, I think, would make more sense from a usability perspective.
In the following code you can call the method CheckDataShowWindow() anytime you wish to show the windows when the data is ready. If you want to add it to another cick handler, you can just make another like so:
public void Another_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
Main code:
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
private void CheckDataShowWindow()
{
if (!DataRepository.IsAllDataLoaded)
{
Timer t = new Timer();
t.Interval = 0.2;
t.AutoReset = false;
t.Elapsed += (s,e) => CheckDataShowWindow();
t.Start();
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}
}
Update
If you can edit the code of the datarepository you should add an event for when the data is done loading.
public delegate void DoneLoadingHandler(object sender, EventArgs e);
public class DataRepository
{
public event DoneLoadingHandler DoneLoading;
//Your loading function
private void LoadAllData()
{
//Load like you do now
//Now fire the event that loading is done.
if(DoneLoading != null)
DoneLoading(this, new EventArgs());
}
}
Now in your other class:
public void FirstMenuItem_Click(object sender, RoutedEventArgs e)
{
CheckDataShowWindow();
}
private bool AllReadyWaiting = false;
private void CheckDataShowWindow()
{
if (!DataRepository.IsAllDataLoaded)
{
if(!AllReadyWaiting)
{
DataRepository.DoneLoading += (s,e) => ShowWindow();
AllReadyWaiting = true;
}
}
else
{
ShowWindow();
}
}
private void ShowWindow()
{
Dispatcher.BeginInvoke(new Action(() =>
{
IndividualEntryWindow Window = new IndividualEntryWindow();
Window.Show();
}));
}

window.ShowDialog stackoverflowexception reasons. WPF

What is main reasons for window.ShowDialog() stackOverflowException in WPF? I receive this exception after 10-20 seconds when I call:
if(myWindow.ShowDialog() == true)
{
//other stuff
}
Window is shows up and works good, but then I receive this exception.
The generic cause of an SOE like this is having an event handler whose code causes the same event to be raised again. A simple example is:
private void textBox1_TextChanged(object sender, TextChangedEventArgs e) {
textBox1.Text += "a";
}
Type a letter, takes about 5 seconds for program to run out of stack space and bomb. Your primary weapon to diagnose exactly which event handler causes this problem is the debugger, look at the Call Stack window. You solve it by using a little helper variable that indicates that you expect the event to be fired again so you can ignore it. Like this:
bool changingText;
private void textBox1_TextChanged(object sender, TextChangedEventArgs e) {
if (changingText) return;
changingText = true;
try {
textBox1.Text += "a";
}
finally {
changingText = false;
}
}
The try/finally is not strictly necessary but wise if you expect to keep your program running after an exception.
Surprisingly a stack overflow exception can be caused by repeatedly calling window.ShowDialog asynchronously.
public MainWindow()
{
InitializeComponent();
TheCallDelegate = TheCall;
_timer = new DispatcherTimer();
_timer.Tick += _timer_Tick;
_timer.Start();
}
DispatcherTimer _timer = null;
void _timer_Tick(object sender, EventArgs e)
{
_timer.Dispatcher.BeginInvoke(TheCallDelegate);
}
Action TheCallDelegate;
void TheCall()
{
Window win = new Window();
win.ShowDialog();
}
As you can see there is no actual recursion here (or there shouldn't have been) but once the exception happens you can see that the call stack is indeed full.
Without looking at how Window.ShowDialog is implemented internally I can't say what is the deeper cause of this.

Categories