Wpf Application Startup appears to run twice - wpf

I have a multi project WPF application, the startup project has now more than this as it's XAML;
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup" ShutdownMode="OnLastWindowClose">
</Application>
and in the Application_Startup I have the following;
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
SiAuto.Si.Connections = "tcp()"
SiAuto.Si.Enabled = True
SiAuto.Main.LogMessage(My.Application.Info.Title & " started")
Dim controller As New MainRibbonController(New MainRibbonService)
controller.Start
End Sub
SiAuto is simply a logging operation. When I start the application I get two entries in the log generated by the SiAuto log message line and then I end up with two MainRibbonForms. Clearly the Application_Startup is running twice but I cannot figure out why.
Has anyone seen this sort of behaviour before and could suggest where I ought to be looking to rectify the issue. Unfortunately WPF and XAML is still relatively new to me and I'm really not sure where I should be looking.
Option strict On across all projects, everything compiles without error, so my guess is that I've made some stupid syntax error somewhere of have failed to comprehend how WPF applications really start.
If I replace all of the application_startup code with just
MessageBox.show("Hi")
I end up with two message boxes.

I had exactly the same problem: my Application.xaml is
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup">
<Application.Resources>
</Application.Resources>
</Application>
The Application_Startup sub fired twice: if I tried to create a new main window and show it, when I started the application two windows were shown. If i put a simple MsgBox in the sub, the message was shown twice.
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
MsgBox("Application_Startup")
End Sub
The problem seemd to be the "Handles" clause. The signature of the sub have to be
Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
without 'Handles Me.Startup'
wpf vb.net

Related

Closing Settings dialog causes application to quit

So here's the setup. I have a standalone WPF application which I've built with VB. Contained in the application is two windows, MainWindow and SettingsWindow, which opens as a dialog and is called from a subprocedure in MainWindow.xaml.vb on the event of a clicked "Settings" button (I like working with code-behind much better than XAML if I can help it).
In SettingsWindow.xaml.vb, I have a subprocedure handling the event of clicking a close button in the window. It executes Me.Close(). The intent is to close SettingsWindow and return focus to MainWindow, but instead, the entire application terminates.
Additionally, clicking the close button in MainWindow closes MainWindow, but doesn't terminate the application in Visual Studio's debug mode, while closing SettingsWindow does.
When building the application and running it outside of Visual Studio (running the .exe itself in Windows), closing SettingsWindow returns to MainWindow as intended, but attempting to re-open SettingsWindow causes the entire application to crash.
I'm relatively new to Visual Studio, and I can post code as needed. Thanks ahead of time for the help.
First, here is my `Application.xaml.vb' file handling app startup:
Class Application
Public Shared initmain As MainWindow = New MainWindow()
Public Shared Sub AppStart() Handles Me.Startup
initmain.UpdateSettings()
initmain.Show()
End Sub
End Class
The code above checks My.Settings, which works fine, then calls MainWindow open.
Here is the code in the MainWindow sub calling SettingsWindow:
Private Sub SettingStart() Handles SettingsButton.MouseUp
Dim SettingWin As SettingsWindow = New SettingsWindow()
' "If" blocks here that check My.Settings before opening the window
SettingWin.ShowDialog()
End Sub
Finally, here is the code that closes SettingsWindow:
Private Sub CloseButtonClick() Handles CloseButton.MouseUp
Me.Close()
End Sub
If you need it, here is Application.xaml:
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="AppStart">
<Application.Resources>
</Application.Resources>
</Application>
Update:
It looks like the issue has to do with the fact that the instance of MainWindow in Application.xaml.vb is Public Shared, but I need to be able to call to that instance from other places to update settings in realtime, so I can't change this. Workarounds?
Additionally, the program now functions properly outside of Visual Studio, no longer crashing.
You need to set the ShutdownMode="OnLastWindowClose" in Application.xaml
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnLastWindowClose" >
<Application.Resources>
</Application.Resources>
</Application>
MainWindow.xaml.vb
Class MainWindow
Private Sub ButtonSetting_Click(sender As Object, e As RoutedEventArgs) Handles ButtonSetting.Click
Dim SettingWin As SettingWindow = New SettingWindow()
Dim rslt As Boolean = False
rslt = SettingWin.ShowDialog()
End Sub
End Class

Application.Current.MainWindow is null in startup event handler

I have a strong background in windows forms, and I'm starting to work in WPF. Consider the following event handler in my Application code behind:
Private Sub Application_Startup(ByVal sender As Object, ByVal e As System.Windows.StartupEventArgs) Handles Me.Startup
Debug.Print(Application.Current.MainWindow Is Nothing)
End Sub
This prints "True", meaning the Application.Current.MainWindow is null. How can I access the main window instance as soon as the application is run? (i.e. I know this event is fired as soon as the application is run)
"If you need access to the main window during startup, you need to manually create a new window object from your Startup event handler." - source: http://msdn.microsoft.com/en-us/library/system.windows.application.startup(v=vs.110).aspx
So basically you will have to create your main window when the Application.Startup event is called. Also you can remove StartupUri="MainWindow" from your App.xaml and simply show the instance of main window you create.
App.xaml
<Application x:Class="Namespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml" <---- Remove this
Startup="Application_Startup"
>
<Application.Resources>
</Application.Resources>
</Application>
App.xaml.cs
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow wnd = new MainWindow();
wnd.Show();
}
I hope this answers your question.

Internet Explorer instance DocumentComplete not firing

I am trying to create an instance of Internet Explorer from a WPF application, load a saved local file, and do some further processing once the file is loaded. However, although the file is visible in the Internet Explorer window, the DocumentComplete event never fires:
'static field
Dim iex As ShDocVw.InternetExplorer
Public Sub DoStuff()
Dim path = "c:\test.htm"
iex = New SHDocVw.InternetExplorer
iex.Visible = True
AddHandler iex.DocumentComplete, Sub(o As Object, ByRef url As Object)
'This code is never executed
Dim i = 5
End Sub
iex.Navigate2(path)
End Sub
When I navigate to a non-local URL (e.g. http://www.google.com) the DocumentComplete event does fire.
The same behavior exists for the NavigateComplete2 event.
I tried using a class member method instead of a lambda expression (maybe the lambda expression is going out of scope once the method exits?) using both AddressOf and Handles, but that didn't help.
What do I have to do to have the DocumentComplete event fire?
(NB: The page has no frames.)
Update
This code is being used in a class library, and I therefore cannot use the WebBrowser control, as it cannot be instantiated in code.
As SimonMourier points out in the comments, a WebBrowser can be instantiated in code:
Dim wb = New WebBrowser
AddHandler wb.LoadCompleted, Sub(s, e)
Dim i = 5
End Sub
wb.Navigate(path)
Although the LoadCompleted event still doesn't fire, the Navigated event does, and it appears to be sufficient for my purposes. (Apparently the WebBrowser has to be visible in order for LoadCompleted to fire -- see here and here -- and since I am not using the WebBrowser in the context of a window, I don't think this is even possible in my case.)
You should use the out-of-the-box standard WebBrowser Control that ships with WPF (there is another one for Winforms apps). It has all the basic events directly supported.
Should you miss some Winforms feature like IsWebBrowserContextMenuEnabled or ScriptErrorsSuppressed, I suggest you refer to my answer in this question on SO: How to deactivate "right click" on WPF Webbrowser Control?
You only need interop in these special cases or if you need to get ahold on the native underlying IE's Document Object Model (DOM), interfaces like IHTMLDocument2, etc.
Instead of using ShDocVw.InternetExplorer you can use WebBrowser control provided by WPF:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<WebBrowser x:Name="webBrowser" Visibility="Visible" />
</Grid>
</Window>
Class MainWindow
Public Sub DoStuff()
Dim path = New Uri("c:\test.htm")
AddHandler webBrowser.LoadCompleted, Sub(sender As Object, e As System.Windows.Navigation.NavigationEventArgs)
Dim i = 5
End Sub
webBrowser.Navigate(path)
End Sub
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
DoStuff()
End Sub
End Class
There is no need to use WebBrowser Control to get this issue resolved.
I have also faced this issue and it happens due to the access privileges.
Run your application with Admin privileges and it will be fine.
To debug try running your Visual Studio as Administrator and then test, The DocumentComplete event will be fired.
Update1:
In case of non-admin application if you can manage to get the internet explorer started with Admin privileges then also you can work with it using your non-admin application.
Simple start a Internet Explorer process with admin privileges.
Then you can hook it using this code
For Each IE As InternetExplorer In New SHDocVw.ShellWindows
If IE.FullName.ToLower.Contains("iexplore") And IE.LocationURL <> "" Then
'Capture IE here
End If
Next

WPF SelectionChange Event for ComboBox with Binding from database crashes the Program

I've got a big issue trying to modify the ItemSource for a ComboBox. When I try to debug the app by putting a breakpoint on MessageBox.Show(...) in the Sub cboTest_SelectionChanged (see below), I get this error:
An Unhandled exception of type 'System.InvalidCastException' occured in Data.exe
Additional Information:
Unable to cast object of type 'System.Data.DataRowView' to type 'System.Windows.Controls.ComboBoxItem'
How can I fix this?
Here's what I do. I create an ACCESS 2007 Database named SNIGDoFFE.accdb, my solution is named Data, I added the Database through the Add New Source Configuration wizard and I drag and drop the Field "Libelle" from the Table Ethnie to the the ComboBox, so it modifies my files like this:
In MainWindow.xaml.vb
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs) Handles MyBase.Loaded
Dim SNIGDoFFEDataSet As Data.SNIGDoFFEDataSet = CType(Me.FindResource("SNIGDoFFEDataSet"), Data.SNIGDoFFEDataSet)
'Load data into the table Ethnie. You can modify this code as needed.
Dim SNIGDoFFEDataSetEthnieTableAdapter As Data.SNIGDoFFEDataSetTableAdapters.EthnieTableAdapter = New Data.SNIGDoFFEDataSetTableAdapter.EthnieTableAdapter()
SNIGDoFFEDataSetEthnieTableAdapter.Fill(SNIGDoFFEDataSet.Ethnie)
Dim EthnieViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("EthnieViewSource"), System.Windows.Data.CollectionViewSource)
'EthnieViewSource.View.MoveCurrentToFirst
'I comment this line to leave the combobox empty
End Sub
The code for cboTest_SelectionChanged is:
Private Sub cboTesT_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles cboTesT.SelectionChanged
MessageBox.Show(CType(cboTesT.SelectedItem, ComboBoxItem).Content)
End Sub
In XAML:
<ComboBox x:Name="cboTest" width="120" Margin"184,10,183,134" SelectionChanged="cboTest_SelectionChanged" DisplayMemberPath="Libelle" ItemSource="{Binding Source={StaticResource EthnieViewSource}}" />
In my Resources:
<Window.Resources>
<local:SNIGDoFFEDataSet x:Key"SNIGDoFFEDataSet" />
<CollectionViewSource x:Key="EthnieViewSource" Source="{Binding Ethnie, Source={StaticResources SNIGDoFFEDataSet}}" />
</Window.Resources>
The Solution is built correctly, the main Window loaded correctly, but when I select an item in the combobox, the program crashes. I try to remove all binding and create Item with and everything work, but by binding the source from my database, it crashes again.
The program crashes because you allow the exception to propagate out of your code. To stop the program from crashing, place everything in your SelectedChange event handler in a try catch block.
This should become a standard for all 'windows entry points' into your code. Whether it is an event or a command, if you didn't call it from your code, use a try catch block to stop exceptions from propagating out of your code.
Regarding the error, you are binding data to your ComboBox. When you interrogate the SelectedItem, it will be of the type of the data (in your case, of type System.Data.DataRowView), not a ComboBoxItem.
If you need the containing ComboBoxItem of the selected item, use the ItemContainerGenerator.ContainerFromItem() to find it, for example
Private Sub cboTesT_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles cboTesT.SelectionChanged
Try
Dim combo As ComboBox = CType(sender, ComboBox)
Dim item As ComboBoxItem = combo.ItemContainerGenerator.ContainerFromItem(combo.SelectedItem)
MessageBox.Show(item.Content)
Catch ex As Exception
' Log or display exception.
End Try
End Sub
If you are just after the data, CType the SelectedItem to your datatype (System.Data.DataRowView) and work with it directly.
I hope this helps.
Sorry Mark, to be so long
and again I'm sorry a lot
on msdn forum, they told me that as the binding source is a Table in a database I must use DataRowView instead of ComboBoxItem,
Dim drv As System.Data.DataRowView = CType(cboTest.SelectedItem, DataRowView)
MessageBox.show(drv("Libelle").ToString())
Don't hesitate to help me another time, please.

Setting User Control's DataContext from Code-Behind

This should be pretty easy, but it throws VS2008 for a serious loop.
I'm trying out WPF with MVVM, and am a total newbie at it although I've been developing for about 15 years, and have a comp. sci. degree. At the current client, I am required to use VB.Net.
I have renamed my own variables and removed some distractions in the code below, so please forgive me if it's not 100% syntactically perfect! You probably don't really need the code to understand the question, but I'm including it in case it helps.
I have a very simple MainView.xaml file:
<Window x:Class="MyApp.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="800" Name="MainWindow">
<Button Name="Button1">Show Grid</Button>
<StackPanel Name="teststack" Visibility="Hidden"/>
</Window>
I also have a UserControl called DataView that consists of a DataGrid:
<UserControl x:Class="MyApp.Views.DataView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfToolkit="http://schemas.microsoft.com/wpf/2008/toolkit" >
<Grid>
<WpfToolkit:DataGrid
ItemsSource="{Binding Path=Entries}" SelectionMode="Extended">
</WpfToolkit:DataGrid>
</Grid>
</UserControl>
The constructor for the DataView usercontrol sets up the DataContext by binding it to a view model, as shown here:
Partial Public Class DataView
Dim dataViewModel As ViewModels.DataViewModel
Public Sub New()
InitializeComponent()
dataViewModel = New ViewModels.DataViewModel
dataViewModel.LoadDataEntries()
DataContext = dataViewModel
End Sub
End Class
The view model for DataView looks like this (there isn't much in ViewModelBase):
Public Class DataViewModel
Inherits ViewModelBase
Public Sub New()
End Sub
Private _entries As ObservableCollection(Of DataEntryViewModel) = New ObservableCollection(Of DataEntryViewModel)
Public ReadOnly Property Entries() As ObservableCollection(Of DataEntryViewModel)
Get
Return _entries
End Get
End Property
Public Sub LoadDataEntries()
Dim dataEntryList As List(Of DataEntry) = DataEntry.LoadDataEntries()
For Each dataentry As Models.DataEntry In dataEntryList
_entries.Add(New DataEntryViewModel(dataentry))
Next
End Sub
End Class
Now, this UserControl works just fine if I instantiate it in XAML. When I run the code, the grid shows up and populates it just fine.
However, the grid takes a long time to load its data, and I want to create this user control programmatically after the button click rather than declaratively instantiating the grid in XAML. I want to instantiate the user control, and insert it as a child of the StackPanel control:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
Dim dataView As New DataView
teststack.Children.Add(dataView)
End Sub
When I do this, as soon as the Button1_Click finishes, my application locks up, starts eating RAM, and hits the CPU about 50%.
Am I not instantiating my UserControl properly? It all seems to come down to the DataContext assignment in DataEntry's constructor. If I comment that out, the app works as expected (without anything in the grid, of course).
If I move this code block into Button1_Click (basically moving DataEntry's constructor code up a level), the app still fails:
dataViewModel = New ViewModels.DataViewModel
dataViewModel.LoadDataEntries()
dataView.DataContext = dataViewModel
I'm stumped. Can anybody give me some tips on what I could be doing wrong, or even how to debug what infinite loop my app is getting itself into?
Many thanks.
The root cause of your issue appears to be either the raw amount of data you're loading or some inefficiency in how you load that data. Having said that, the reason you're seeing the application lock up is that you're locking the UI thread when loading the data.
I believe that in your first case the data loading has been off loaded onto another thread to load the data. In you second example you're instantiating the control on the UI thread and as a result all the constructor and loading logic is performed on the current thread (the UI thread). If you offload this work onto another thread then you should see similar results to the first example.
I eventually gave up on trying to get the DataContext on the UserControl set during instantiation of the UserControl (either in XAML or code). Now I load up the data and set the DataContext of the UserControl in an event in the UserControl (IsVisibleChanged, I believe). When I instantiate the UserControl in XAML, I have it's Visibility set to Hidden. When Button1 is clicked, I set the UserControl's Visibility to Visible. So the UserControl pops into view, and it loads up its data and DataContext is set. Seems to work, but also seems very kludgey. :-( Thanks for the help, folks!
If it's only a matter of your control taking a long time to populate data, you should populate the control on another thread then add it through a delegate:
Since I'm not too good at writing VB.NET, but here's the C# equivalent:
private void Button1_Click(Object sender, RoutedEventArgs e)
{
Thread thr = new Thread(delegate()
{
DataView dataView = new DataView();
this.Dispatcher.BeginInvoke((Action) delegate()
{
teststack.Children.Add(dataView);
});
});
thr.Start();
}

Resources