Window.Current.Activated not fired on every UI interaction - c#

I am working on UWP application and I'm having a logic that depends on application focus gain/loss:
...
Window.Current.Activated += Current_Activated;
...
//My code depends on this flag
public bool IsViewCurrentlyInFocus { get; private set; }
private void Current_Activated(object sender, WindowActivatedEventArgs e)
{
IsViewCurrentlyInFocus = e.WindowActivationState != CoreWindowActivationState.Deactivated;
}
What I've notice is that user can interact with my application (for instance: scrolling the listview) although the event isn't raised - only when tapping/clicking on the page...
How can I determine that some sort of interaction is made with my application?
Thanks in advance

Please see the documentation:
Occurs when a window becomes the foreground window.
In a nutshell, this is a Window event, it does not affect the elements within the window. In your scenario, you can make use of the IsActive property to determine whether your Window is being used. For individual elements, I would suggest using the GotFocus event and IsFocused property respectively.
If you are specifically trying to detect the scroll in a ListView, this isn't possible, however you can check this answer.

Related

Using Mouse.Capture to detect a click outside of a given control

I have a TextBox in a WPF project where I am trying to detect a mouse click anywhere on the Application other than in the TextBox.
Here is the code that I have so far.
System.Windows.Input.MouseButtonEventHandler clickOutsideHandler;
public MyClass() {
clickOutsideHandler = new System.Windows.Input.MouseButtonEventHandler(HandleClickOutsideOfControl);
}
private void StartCapture() {
System.Windows.Input.Mouse.Capture(TextBox1, System.Windows.Input.CaptureMode.SubTree);
AddHandler(System.Windows.Input.Mouse.PreviewMouseDownOutsideCapturedElementEvent, clickOutsideHandler, true);
}
private void HandleClickOutsideOfControl(object sender, System.Windows.Input.MouseButtonEventArgs e) {
ReleaseMouseCapture();
RemoveHandler(System.Windows.Input.Mouse.PreviewMouseDownOutsideCapturedElementEvent, clickOutsideHandler);
}
The problem I'm having is that the event handler never gets called. I've tried capturing the return value of the Capture() function, but it shows as true. Can anyone show me what I'm doing wrong?
You could instead use LostFocus / LostKeyboardFocus but there has to be another element on the window that can get focus.
Second approach that does more what you what exactly ( yet doesn't make total sense) would be to attach to the global mouse down. Intercept every mouse click to WPF application
then on that one do a hittest and determine what is underneath.https://msdn.microsoft.com/en-us/library/ms608753(v=vs.110).aspx

MessageBox changes something seemingly unrelated

Here's my setup: I have a TabControl with numerous tabs, and on the last tab, I have a UserControl that is added to a TabPage. This UserControl has a VisibleChanged event that is supposed to check if it is visible, and if it is displays certain information using CustomCommand().
void MyUserControl_VisibleChanged(object sender, EventArgs e)
{
//MessageBox.Show("");
UserControl us = sender as UserControl;
if (us.Visible)
{
CustomCommand();
}
//MessageBox.Show("");
}
Here is the problem: this code as-is will incorrectly think the UserControl is visible when it is not, and the CustomCommand() will run when it's not supposed to. When the commented-out MessageBox function is un-commented in either spot, the UserControl is correctly seen as not visible until, of course, the TabPage is selected. Does anyone have any idea why this would be?
Just putting it on a TabPage doesn't explain this problem. There must be other layout events involved that make the control actually visible later. The MessageBox.Show() call provides the time machine to get the Visible property checked with a delay.
The standard technique to get code to run later, the way MessageBox does, is by using the Control.BeginInvoke() method. The delegate target runs when all events have been fired and processed and the UI thread goes idle again. Like this:
void MyUserControl_VisibleChanged(object sender, EventArgs e)
{
UserControl us = sender as UserControl;
this.BeginInvoke(new Action(() => {
if (us.Visible)
{
CustomCommand();
}
});
}
Not sure if this will help you, but there is a strange, and afaik undocumented, asymmetrical behaviour with the Visible_Changed event:
It does get raised whenever the Visible property of the control changes, either to true or to false.
It also get raised whenever the Parent's Visible property changes to true and only to true!
I could not raise the event by hiding the Control by another control, or for that matter by the MessageBox, though.
I don't know how your application works, so I could not reproduce. But I did notice that indeed, when changing tabs the Visible_Changed event of a Control on the TabPage does get raised, whenever the page is selected (but not when it is unselected.) I didn't know either.
You can try to catch the other direction by either going for the SelectionIndexChanged or by hooking into the VisibleChanged event of the TabPage. This is not visible in the IDE, but it does work both ways:
tabPagexyz2.VisibleChanged += tabPagexyz_VisibleChanged;
void tabPage2_VisibleChanged(object sender, EventArgs e)
{
// do something
}
I saw wild guesses about UI race conditions being behind it, which I doubt. This would at least explain why a MessageBox would habe an influence. If you want to test, you could replace it with one the evil Applictaion.DoEvents.

Windows Forms Binding: is there an event similar to DataBindingComplete, but fired when ALL bindings are completed?

I need to change a certain DataGridView's property (a DataSourceUpdateMode for one of its binding) only when ALL of its initial data bindings are completed.
I tried subscribing to the "DataBindingComplete" event, but it's fired too many times (one or more time for each binding associated to the control); what I need is a more global "AllDataBindingsComplete" event, fired when the control is ready to be displayed to the user.
As a temporary workaround, I'm using the MouseDown event (I've assumed that when the user is able to click the control, it means that the control is displayed... :) and the events I'm playing with - SelectionChanged - are fired after the MouseDown):
protected override void OnMouseDown(MouseEventArgs e)
{
Binding selectedItemsBinding = this.DataBindings["SelectedItems"];
if (selectedItemsBinding != null)
{
selectedItemsBinding.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
}
base.OnMouseDown(e);
}
It works, but it smells like an ugly hack A LOT (and it's called too many times, only one time is enough for my needs).
Is there a better way?
(yes, I'm trying to adopt MVVM in a Windows Forms project, and I've added a bindable "SelectedItems" property to the DataGridView...)
What I've done at the Windows Forms form level, and may be improvised down to just the control(s) you want, is to subclass the Windows Forms baseclass into my own. Then, in its constructor, attach an extra event call to the Load() event.
So when everything else is completely loaded, only THEN will it hit my custom method (of the subclass). Since it is the bottom of the call-stack chain being attached to the event queue, I know it's last and everything else is done... Here's a snippet of the concept.
public class MyForm : Form
{
public MyForm()
{
this.Load += AfterEverythingElseLoaded;
}
private void AfterEverythingElseLoaded(object sender, EventArgs e)
{
// Do my own things here...
}
}
This concept can be applied to the Init() function too if that's more appropriate for your control... Let everything else within it get initialized(), then do you the "AfterInitialized()" function.

Loaded event of a WPF user control fires more than once

To implement a tab-based environment in WPF we need to convert our forms to user controls, however when doing this, the Loaded event of the user control is called two times.
While searching on the internet other people also pointed this issue. How can we ensure that loaded event is called only once? Because when it is called multiple times, initialization of our controls happens multiple times.
As explained in this blog, the Loaded event is fired when ever a control is about to be rendered (i.e. added to the visual tree).
There are several controls that would cause your control to be loaded/unloaded multiple times. For example, the native WPF TabControl only renders the content of the selected tab. So when you select a new tab, the content of the previously selected tab is unloaded. If you click back to the previously selected tab, then it's content is reloaded.
One work around is to use a Boolean to flag whether you have already initialized your control, as suggested by others. Alternatively, you may be able to use the Initialized event instead.
Your routed event handler can (and should) remove itself from the Loaded hook as the first thing it does.
public class MyClass : Window
{
public MyClass()
{
Loaded += MyLoadedRoutedEventHandler;
}
void MyLoadedRoutedEventHandler(Object sender, RoutedEventArgs e)
{
Loaded -= MyLoadedRoutedEventHandler;
/// ...
}
};
Set a loaded flag in the event, and, if the flag has already been set, don't do anything.
As mentioned above,you can use bool flag for it.
bool isPageLoadingForFirstTime = true;
public void LoadedEvent()
{
if(ispageLoadingForFirstTime)
{
//do something
ispageLoadingForFirstTime = false;
}
}

Handling the "X" close button in WPF under MVVM

I'm creating a basic database application in WPF, and I have started using the MVVM pattern.
I have a dialog that asks the user to select an item from a ListBox and click "OK." After that, I take the item the user clicked from a property in the view model and pass it into another dialog. But if the user clicks "Cancel," I set that value to null, and the action is canceled: I don't open the next dialog and return to the main screen. Example:
public class SelectEquipmentViewModel : WorkspaceViewModel
{
private bool _selected;
public Equipment SelectedEquipment
{
// Item selected by the user
}
// Action for "SelectCommand," which is attached to
// the "Select" button in the view
public void ExecuteSelect()
{
_selected = true;
// Fires a RequestClose event in WorkspaceViewModel,
// which is attached to the view's Close method
RequestClose();
}
public override void RequestClose()
{
if (!_selected)
{
// The user clicked "Cancel"
SelectedEquipment = null;
}
base.RequestClose();
}
}
This has been working great, but the problem comes if the user clicks the red "X" close button in the window's control box. The RequestClose method never gets invoked, and the selected item isn't set to null, which is bad.
I've considered attaching the view model to the Closing event of the view, but I feel this could get messy if I start creating handlers for all these events.
What would be the "preferred" way of handling this situation?
Thanks.
I think that using the EventToCommand behavior to wire up the Window object's Closing event to a new ExecuteCancel command is pretty clean.
public void ExecuteCancel()
{
_selected = false;
// Fires a RequestClose event in WorkspaceViewModel,
// which is attached to the view's Close method
RequestClose();
}
Where do you think this will get messy? If you add a Cancel button, it could use the same ExecuteCancel bits...
Behaviors are what you want to use to execute a command when the user presses the "X" button on window using MVVM. Check out Reed Copsey's blog here: http://reedcopsey.com/2009/10/09/using-behaviors-to-allow-the-viewmodel-to-manage-view-lifetime-in-m-v-vm/
You can download a sample application here...
I use this method all the time to allow the ViewModel manage the life of the view.
Approach without additional dependencies is described in article Handling a Window's Closed and Closing events in the View-Model and code with example provided. This does not add code behind xaml.
(Thanks to Reed Copsey's link)

Categories