Application.Current.MainWindow.Close vs Application.Current.Shutdown - wpf

Should Application.Current.Shutdown() NOT be used as a best practice to close a WPF application?
I have a small, multiple window application and the "shutdown" seems to work nicely for all my exit commands. However, I have been told to always use Application.Current.MainWindow.Close().

MainWindow.Close won't even do anything if the ShutdownMode is not set respectively. You can do what you want, it should just fit what one expects.
(Shutdown will ignore the fact that some Closing event was cancelled, so that would be one thing you need to take into consideration)
Also:
Shutdown is implicitly called by Windows Presentation Foundation (WPF) in the following situations:
When ShutdownMode is set to OnLastWindowClose.
When the ShutdownMode is set to OnMainWindowClose.
When a user ends a session and the SessionEnding event is either unhandled, or handled without cancellation.

Related

Send call open event from the event ItemChanged of a DataWindow

I try to send for the Open event of the window from the event ItemChanged a DataWindow using the: SUPER :: EVENT OPEN () in addition to the open event contains "script ancestor" I also need to run; itself need to restart the window from the event ItemChanged of a DataWindow.
I hope your help.
Thanks in advance.
Regards,
A few things jump out from your question.
SUPER::EVENT OPEN() will try to call the Open event of the DataWindow if called from the ItemChanged, not the Window.
I'm not 100% sure of this, but I'm pretty sure I've run into problems trying to call the ancestor of one script from a completely different script. I can't point to documentation; I'll have to just chalk it up to experienced suspicion.
It's not entirely clear what you're after, but if you want to call the Open of the window (and I'll suggest otherwise below), and if the window's Open script either extends the ancestor script or explicitly calls the ancestor script (as above), explicitly calling the ancestor script is unnecessary, and strikes me as potentially undesirable. Just call the Open script of the window you're writing.
This will depend entirely on your code, but of the dozens of systems I've had to maintain, I'd never assume that running the Open event of a Window would "restart" the window. Most systems I've worked on, that would just create an unexpected mix of previous and new states. Additionally, even if I coded this from scratch to work perfectly in this way, I'd assume that the next guy that came along to maintain my code (after I won the lottery and retired to a small South Pacific island) would code in a way that made perfect sense to him based on other systems he worked on, but would screw up my assumptions. If I needed to "restart" the window, I would either:
close the window and post an Open() (the function, not the event) of the window again
create a ue_ResetWindow event, hopefully coding so that the Open could use it as well, that made it obvious that anything added to the window needed to be maintained in this script as well
(Of the two, the latter would be far better user experience and coding, IMHO.)
Good luck,
Terry.

Graceful application shutdown using WPF PRISM 4

I'm looking for a "best practice" (if there is even a best) for cleanly shutting an WPF application down that uses MEF and PRISM4. Ultimately, I'm looking for some sort of "Close Service" would manage all of event/commanding from the Shell to any viewmodel (or other subscribers) that want to verify it's OK to close the application. Is the event aggregator the cleanest way? Other opinions/options?
Ideally, I'd have a button on my ToolbarView in my ToolbarRegion (1 of 2 regions in my Shell). This button would invoke a command on my ToolbarViewModel (referencing a command on my ToolbarControler) which in turn would do 2 things (I think?)...First, notify all subscribers that it's closing time and allow any of them to cancel the close and...secondly, if none cancel, somehow notify the shell to close. My app's shutdown mode is set to "ShutdownMode.OnMainWindowClose" so if the Shell closes, I should be all set.
Can someone help me out with this?
I'm developping a large application using the same stuff: MEF and PrismV4
I handle shutdown it a bit differently:
in the Shell, there is a "Tools" Region, shutdown for that is handled right in the Shell, on the close event.
Then for everything injected in the other region, which is a tabcontrol, I cast the content as IDisposable, and close every tab one by one. (Actually, it's not a tabcontrol, it's an avalondock component, but it's the same thing really).
Of course, you'll have to implement IDisposable on every class that has references etc to dispose, but it's hard to think of a "clean way of shutting down" without meantioning that interface right? =)
Now, about the EventAggregator: you may very well run into trouble, because there is no coupling: you can fire a weak event through it, but you can't wait for objects to do their work after that.
And then, you couldn't make a mechanism to cancel the shutdown.
In case you want your various views to be able to cancel the shutdown, i suggest you create an interface with a single method in it:
public interface IShutdownAware
{
bool CanShutdown();
}
Then right before you call dispose, call CanShutdown(); if they all return true, proceed with disposing, otherwise, cancel the shutdown process.

WPF performance problem with CommandManager

We've created a new, quite complex, WPF application from the ground up and have run into a performance problem as the number of commands registered with the CommandManager increase. We're using simple lightweight commands in our MVVM implementation, however the third party controls we're using (Infragistics) do not, and call CommandManager.RegisterClassCommandBinding liberally to add RoutedCommands. The performance problem manifests itself as a perceived sluggishness in the UI when responding to user input, for example tabbing between controls is slow, text input is 'jerky' and popup animation is 'clunky'. When the app is first fired up the UI is snappy. As more screens containing Infragistics grids are opened the performance deteriorates.
Internally, the CommandManager has a private field named _requerySuggestedHandlers, which is a List< WeakReference>. I've used reflection to get a reference to this collection, and I've noticed that when I call .Clear(), the responsiveness of the UI improves back to its initial state. Obviously I don't want to go round clearing collections that I know little about, especially using reflection (!) but I did it to see if it would cure the performance problems, and voila it did.
Normally, this situation would clean itself up after a certain amount of time passes. However, the collection of WeakReferences (_requerySuggestedHandlers) will only get trimmed once a garbage collection is initiated, which is non-deterministic. Because of this, when we close down windows containing grids (Infragistics XamDataGrid), the CanExecute property for 'dead' grid commands continue to be evaluated unnecessarily, long after the window is closed. This also means that if we close down a number of windows, the performance is still sluggish until a garbage collect is initiated. I understand that this can happen on allocation, and I've seen that myself because if I open a further window this causes the initial memory (from the disposed Windows) to be collected and performance returns to normal.
So, given the above, here are my questions:
How, and from where, does CommandManager.InvalidateRequerySuggested() get called? I haven't found any documentation on MSDN that explains this in any great detail. I hooked up to the CommandManager.RequerySuggested event and it looks like it's being called whenever controls lose focus.
Is is possible to suppress CommandManager.InvalidateRequerySuggested() being called in response to user input?
Has anyone else run into this issue, and if so, how have you avoided it?
Thanks!
This sounds like one of the rare cases where deterministically calling GC.Collect() is the right thing to do. The ordinary argument against it is that the garbage collector is smarter than you are. But when you're dealing with WeakReference objects, you enter territory where you may know something that the garbage collector doesn't. Kicking off garbage collection is certainly better than clearing _requerySuggestedHandlers - among other things, it won't do anything to the WeakReference objects that point to controls that are still alive.
I'd choose this over trying to figure out how to suppress RequerySuggested, since that would screw up the behavior of those commands that you still care about.

WPF command not executable

I have a button on a toolbar that has its command set to "MyControl.Print" (for example).
In the control the command is added to the command bindings including both the Execute and CanExecute.
The control is within a window with other controls docked appropriately.
I am finding that for the Print button to be enabled I have to "select" MyControl first which does not provide a good user experience and indeed causes various "bugs" being raised and lots of confusion.
Is there a way that I can ensure that the button is enabled whether or not the control has been "selected"?
Since the CanExecute doesn't fire, I think you might be looking at the major downside to RoutedCommands - the way they tunnel and bubble can leave a highly composed interface unable to have commands arrive anywhere useful. For this reason we ended up moving to DelegateCommands from (I think) the Microsoft CAG. Not any of the other stuff, just the commands. Works a lot better, and isn't tied in to the interface so tightly.
Oh, the other response raises a good point. I assumed you meant that to ever print, your MyControl needed to have keyboard focus. Is it only the first time and after that it works?
I recommend http://msdn.microsoft.com/en-us/library/ff921126(PandP.20).aspx as a pretty good starting point. You don't have to worry too much about the IActiveAware up front, since you're hoping for this command to be available all the time (or at least let its availablity be determined by CanExecute).
CommandManager.InvalidateRequerySuggested will force the command manager to re-call all of your CanExecute methods and should disable the button. Perhaps call that onload?

Drop outside the control

I'm improving standart WPF TabControl. I want to add undocking functionality to it:
user drags the page just outside the TabControl and this page undocks in the window.
I want two events in this control - PageDragStart (raises when the page dragged outside) and PageDragEnd (raises when the page dropped outside)
I've got no problem with the first event.
But the second... OnDrop doesn't call, because the item dropped outside the tabcontol container. How can I know that it was dropped?
P.S. I want a universal control (so, undocking functionality shouldn't be connected and hardcoded with the window tabcontrol is placed or something like this)
Why use DoDragDrop at all? As I was reading your description, using Mouse.Capture by itself seemed the obvious solution:
Handle OnMouseLeftButtonDown on the tab and start capture
Handle OnMouseMove on the tab and update the cursor based on hit testing
Handle OnMouseLeftButtonUp on the tab, and stop the capture and make the appropriate change
The reasons you might ever consider DoDragDrop over simple mouse capture are:
Integration with Windows' OLE drag and drop so you can drag and drop between applications and technologies
Modal nature of DoDragDrop call (which actually seems to be more of a disadvantage to me)
Automated hit testing of targets
Standardized "drop operation" API to allow unrelated applications to handle copy vs move, etc.
You apparently don't need the OLE integration or multi-application support and you want to customize the hit testing, so it seems that DoDragDrop has no advantages over directly handling the mouse capture.
I solved the problem - in rather brutal and unsafe way. But for it's gonna work as the temporary solution.
Well, when I'm raising PageDragStart event, I call Mouse.Capture(this, CaptureMode.SubTree);
When the page is dropped somewhere - DoDragDrop throws different exceptions (COMException, NullReference (I couldn't find which object is null) and some others I don't remember).
I catch exception and call PageDragEnd event (if the property IsPageDraggingOut set to true).
As far as you can see this solution is really dirty and bad. But it works.
So, any other ideas (or some ideas how to work with Mouse.Capture properly)?

Resources