There are problems using the Loaded event. Can you give may a way to reproduce the exception? If it's complicated can you send me an example project illustrating the exception (send it to support@wyday.com).
I've been trying out wyBuild with my WPF application and had a problem with the AutomaticUpdater.
It seems that the updateHelper is null when it's called in the EndInit() method, throwing a NullReferenceException.
The problem is that even though the control has been instantiated, it has not yet been added to the visual tree. This can happen when using data binding to create the parent control, as is common in some styles of MVVM.
So I made the following changes to AutomaticUpdater/ControlWPF/AutomaticUpdater.cs, which is used by both the 3.5 and 4.0 versions of the control:
1. I added this code to the last line of the AutomaticUpdater constructor:
Loaded += AutomaticUpdater_Loaded;
2. I renamed the ISupportInitialize.EndInit method as AutomaticUpdater_Loaded:
private void AutomaticUpdater_Loaded(object sender, RoutedEventArgs e)
Everything else stays the same. This defers execution to after the control is initialized and loaded, guaranteeing it was added to the Window.
Any chance this fix will make it to the master on Google Code?
There are problems using the Loaded event. Can you give may a way to reproduce the exception? If it's complicated can you send me an example project illustrating the exception (send it to support@wyday.com).
Ok. I've created a sample project and sent it to you by email. Let me know if it didn't get through.
Ok, I got the source -- I'll check it out now.
There are several problems with the fix. It doesn't throw an exception but a large section of code isn't being executed. The Windows's OnLoad event is never called, because the control's Loaded event is called after the Window's OnLoad event. This causes several new large problems.
Unfortunately, due to the way the AutomaticUpdater is designed, you won't be able to add the AutomaticUpdater to a user control, a view, or otherwise. However, you still will be able to add the AutomaticUpdater to Grids, Views, controls, etc, after they've been added to the main Window. The AutomaticUpdater has no problems being a sub-control in other containers (grids, etc.) so long as the AutomaticUpdater was added to the main form.
Does this make sense?
Also, we've added an explanatory exception that will be thrown if the Window can't be found.
While testing your components I stubled about the same issue.When you do MVVM and IOC containers, your bootstrap code might look something like this
protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); RegisterDependencyObjects(); InitializeCulture(); SetDesignTheme(); // Start the show DispatcherHelper.Initialize(); var window = _container.Resolve<MainView>(); window.Show(); }
When starting the application like this, the AutomaticUpdater component doesn't work, as it tries to get the main window, before it is actually shown and therefore before the visual tree has been created, as was pointed out before.
I found now another solution, which I would like to share for review.In the initialize event, I subscribe for the loaded events. Then when a window is loaded, I check if it is the window where the AutomaticUpdater component is located. If yes, basically the original code is executed, as in the original code. This seems to work.
void ISupportInitialize.EndInit() { if (DesignMode) return;
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, new RoutedEventHandler(WindowLoaded)); }
private void WindowLoaded(object sender, RoutedEventArgs e) { ownerForm = Window.GetWindow(this);
if (ownerForm != sender) return;
if (ownerForm == null) throw new Exception("Could not find the AutomaticUpdater's owner Window. Make sure you're adding the AutomaticUpdater to a Window and not a View, User control, etc.");
auBackend.Initialize();
// see if update is pending, if so force install if (auBackend.ClosingForInstall) { // hide self if there's an update pending ownerForm.ShowInTaskbar = false; ownerForm.WindowState = WindowState.Minimized; }
ownerForm_Loaded(ownerForm, new RoutedEventArgs()); }
Your thoughts?
RegardsJg