Understand WPF Window Events - c#

I see Windows have a Loaded event, but not a Loading event (as there is Closing and Closed events).
My expectation was that the Loaded event would occur before the window is actually displayed. However, looking at the Window Lifetime Events, it shows that the Loaded event occurs after Activated event.
I put some initialization code in the Loaded event and there is a delay after the window is displayed and before my content appears. So what is the best event handler to use for window initialization that should occur before the window is displayed?

You can override OnStartup() in App.xaml.cs, and do stuff before calling base.OnStartup(e);. I just checked and this is fired before the window's constructor.
Alternatively, set the window's visibility to Hidden in its xaml file, do your initialization in the constructor and then set the visibility to Visible once done. This won't remove the delay, but the delay is only caused by whatever your initialization code is doing, so it's unavoidable unless you go asynchronous.

Here's a simplified version of what I do (error handling removed). If the initialization takes a while, you may want to display a splash screen while you're doing your thing.
App.xaml:
<Application x:Class="MyProgram.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_StartUp" >
</Application>
App.xaml.cs:
namespace MyProgram
{
public partial class App : Application
{
private void App_StartUp(object sender, StartupEventArgs e)
{
// Create the model and MainWindow
MyModel model = CreateModel();
MainViewModel viewModel = new MainViewModel(model);
MainWindow = new MainWindow(viewModel); // Sets the DataContext
// Do things, like initialize your model
model.Initialize();
// Now show your window
MainWindow.Show();
}
}
}

Related

Is there any way to bubble events up to the MainWindow from a UserControl in AvaloniaUI?

I'm trying to create an Avalonia App which uses several UserControl Views by binding the content in the MainWindow to a property Content in the MainWindowViewModel.(I believe this is standard for MVVM).
I want to be able to handle user inputs such as tapping the screen, pressing buttons etc, while also letting those events to bubble up to the MainWindow so that all inputs from the user can be monitored. This would allow a generic handler which could be simply used update an inactivity timer.
The furthest events seems to be within the same UserControl however I would like to handle the event from the MainWindow. This would mean that everytime a new UserControl is created, the inactivity timer would still function without major changes.
Here is how I'm currently handling tap events on the UserControls:
public static event EventHandler<RoutedEventArgs> TapRegistered;
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void RegisterTap(object sender, RoutedEventArgs e) => IdleWindowView.TapRegistered?.Invoke(this, e);
I'm then simply picking that up on the ViewModel the UserControl.
Let me know if there's any information which could be helpful - I wasn't exactly sure what code to add.
You need to actually register a RoutedEvent via RoutedEvent.Register like this:
public static readonly RoutedEvent<RoutedEventArgs> FooEvent =
RoutedEvent.Register<RoutedEventArgs>(
"Foo",
RoutingStrategies.Bubble,
typeof(YourType));
and then call control.RaiseEvent(new RoutedEventArgs { RoutedEvent = FooEvent }); to raise it.
I was able to detect taps on the MainWindow (And all views), by adding a handler in the code-behind of the MainWindow as shown below:
this.AddHandler(TappedEvent, this.RegisterTap, handledEventsToo: true);
And simply sending an event to the ViewModel to update an inactivity timer as shown below:
private void RegisterTap(object sender, RoutedEventArgs e) => MainWindow.TapRegistered?.Invoke(sender, e);

Wpf usercontrol lost focus event or muse down beyond my control

do you know a "simple" way to detect when a user control loses focus?
I am creating a console output inspired by Visual Studio.
Visual Studio console output collapses when I click anywhere.
Obviously in my application if I click on a Panel (which has no focus) I do not receive any events.
I had thought about using the mouse_down event on the application, but I would have to do an evaluation with every click!
Do you know any way to know when you click out of your control?
UserControl has a LostFocus event. In the code behind of your UserControl you can simply add an event handler.
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
LostFocus += OnFocusLost;
}
private void OnFocusLost(object sender, RoutedEventArgs e)
{
// Do something here.
}
}
If you are referencing it from another class then you can create an event handler on that class and subscribe to the event from the UserControl.
UserControl control = new UserControl();
control.LostFocus += OnFocusLost;
With that being said, if you have a TextBox or some other control inside of the UserControl then the UserControl will lose focus every time a TextBox gets the focus so you will most likely need to write a method to determine if any of the elements inside the UserControl have focus.

Event to know usercontrol's disposal?

if a window with usercontrol is getting closed, then i should call a method in the usercontrol i.e. nothing but when usercontrol is disposed. How do i do that?
If you want to know when the garbage collector collects the UserControl use this:
~UserControl1()
{
//...
}
If you want to know when the UserControl is unloaded from its parent, use Unloaded event on the userControl
note: unlike a Window, a UserControl can't get closed.
As contols do not have a Closing/Closed event it's not that simple as overriding Dispose. Dispose may not be called under some circumstances.
You might override WndProc of the control and catch the WM_CLOSE event.
For future reference for others..
I disposed my user control that was loaded by my main window like this:
<UserControl x:Class="MyApp.Class" ... Unloaded="UserControl_Unloaded"></UserControl>
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
((MyVM)this.DataContext).Dispose();
}
Unloaded is an event available on any View.

wpf combo change event triggered when form loads

I am having a problem, when window loads, the 'selection_change' event associated with 'combo box' control is getting triggered when the window loads first time. Why its occuring and How to restrict it please?
Regards
With that code, the SelectionChanged event won't get raised. Create a new project, paste it and try it for yourself.
My guess is pretty much the same as Sekhar_ Pro's, you're populating your ComboBox from code behind, and something in there causes the SelectedItem to change.
Investigate the cmbUsers.SelectedItem in the cmbUsers_SelectionChanged event handler to see if it has some value or is null in the debugger. Also, look in the Call Stack to find what caused this event to be raised.
Example code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
cmbUsers.Items.Add(new ComboBoxItem { Content = "Test" });
cmbUsers.SelectedIndex = 0;
}
private void cmbUsers_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (cmbUsers.SelectedItem != null)
{
MessageBox.Show(cmbUsers.SelectedItem.ToString());
}
}
}
The Call Stack looks like this for me in the event handler
This is not a normal Behavior, some where you must be doing something like setting SelectedItem, etc which in turn is triggering the event. Check thorough your form's life-cycle events and see if you are doing something like this, may be in Load or Activate event or somewhere in the Constructors.

Hide WPF Window Until Fully Loaded

For my WPF application, I am storing several user settings like window position, window state, and whether or not to display a welcome dialog. The problem is that while everything is loading up, I see a lot of flashing and flickering as the windows are loaded in, and then more flickering when the window is maximized after reading in the settings.
I am already using the built-in WPF PNG splash screen functionality, but is there a way to completely hide the rendering of all windows until everything is fully loaded in?
Edit the Application.xaml, remove the StartUpUri, instead set the StartUp event handler.
In Application.xaml.cs, edit the startup event handler to display the splashscreen, load your resources, create everything, then create the main window and show it.
<Application
...
StartUp="OnStartUp"
/>
And:
private void OnStartUp(Object sender, StartupEventArgs e)
{
var settings = LoadSettingsFrom... // Call your implementation of load user settings
// Example only, in real app do this if's section on a different thread
if (settings.doShowSplashScreen)
{
var splashScreen = new SplashScreen();
splashScreen.Show();
}
// Load and create stuff (resources, databases, main classes, ...)
var mainWindow = new mainWindow();
mainWindow.ApplySettings(settings); // Call your implementation of apply settings
if (doShowSplashScreen)
{
// send close signal to splash screen's thread
}
mainWindow.Show(); // Show the main window
}
You can set the windows WindowState to Minimized, then handle the ContentRendered event and set the WindowState to Normal or Maximized.
There are functions , BeginInit and EndInit, if you change properties inside these functions like..
BeginInit();
...
... // Do your code Initialization here...
...
EndInit();
then your window will not render until the EndInit() is called, it will not flicker.
When does this loading occur? Code executed in the main Window's constructor should execute before the window is shown; if you load any required resources there, you should not see any flickering.

Categories