Closing Settings dialog causes application to quit - wpf

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

Related

Visual basic: '<name>' is not a member of '<classname>'

Before you read, here are a couple pages I have looked at before posting this question:
'Button_Click' : is not a member of 'ButtonTest::MainPage'. This question regards C++ and is not useful as far as I am aware. According to the only answer, you need to "define the prototype of MainPage::Button_Click in the MainPage.xaml.h file as a member of the class."
visual basic error BC30456 'Form1' is not a member of 'WindowsApplication1'. This question also experiences the same error, however it is caused by something else. The OP replied to this answer, saying that it fixed the problem:
If you have renamed the startup form1 it is likely you also have to change the Startup form setting. You can find this setting to open 'My Project' in the 'Solution Explorer'. Select the Application section, change the 'startup form' as appropriate.
In my case, I have not renamed anything since making the project, and the code which the error points to is a line which adds a handler in 'popup.g.i.vb'
I also looked on MSDN: Creating Event Handlers for WPF Controls. The page uses the following syntax to react to a button being clicked:
<Button Click="Button2_Click" />
and
Sub Button2_Click(ByVal Sender As Object, ByVal e As RoutedEventArgs)
'Code here
End Sub
This is exactly the same syntax as I have used.
My code
I am currently making a program using WPF and Visual Basic, and I wanted to make a small window pop up if the user causes an error.
I have a WPF window named popup.xaml and I have a class called 'popup' which inherits from 'window'. I want to create a window and then close it when the user clicks the 'ok' button. The equivalent of this in C# would be the following:
popup errorWindow = new popup("Error message here");
errorWindow.ShowDialog();
When this method is called, an override of popup() is called which initialises and also takes the error message as a parameter.
public partial class popup : Window
{
public popup()
{
InitializeComponent();
}
public popup(string errorMessage)
{
InitializeComponent();
this.errorMessage.Text = errorMessage;
}
private void okButton_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
When the 'ok' button is clicked, the okButton_Click() method is called and the window closes.
In my visual basic application, I have the same WPF code for the error window:
<Window x:Class="FacialRecognitionVB.popup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FacialRecognitionVB"
mc:Ignorable="d"
Title="Error." MinHeight="150" MaxHeight="150" Height="150" MinWidth="300" MaxWidth="300" Width="300" >
<Grid>
<Border VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Gray" />
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5" >
<TextBlock x:Name="errorMessage" FontSize="18" FontWeight="Medium" Text="An error has occured." TextWrapping="Wrap" />
</StackPanel>
<Button x:Name="okButton" Template="{StaticResource ButtonTemplate}" Content="OK" Width="40" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="5,5,5,5" Click="okButton_Click" />
</Grid>
Despite this, the event handler for clicking the button is playing up. The VB code for my popup class is almost exactly the same:
Partial Public Class popup
Inherits Window
Public Sub Popup()
End Sub
Public Sub Popup(ByVal message As String)
Dim errorMessage As TextBlock
errorMessage.Text = message
End Sub
Private Sub okButton_Click(sender As Object, e As RoutedEventArgs)
Me.Close()
End Sub
End Class
I create an instance of the class using this code in MainWindow.vb:
Dim errorWindow As New popup()
errorWindow.Popup("An error has occured.")
When I try to build this, I get the error 'okButton_Click' is not a member of 'popup'. On double-clicking the error in the error list it takes me to popup.g.i.vb and highlights the following:
#ExternalSource ("..\..\popup.xaml", 14)
AddHandler okButton.Click, New RoutedEventHandler(AddressOf Me.okButton_Click)
#End ExternalSource
It will not give me any further information other than 'okButton_Click' is not a member of 'popup'
How can I fix this? I actually have several buttons on my main page which work perfectly using visual basic! This one button, for some reason, does not. Is there something different I need to do because it is on a separate window as part of a popup?
Update
I had another look round today and I found '{name}' is not a member of '{classname}' on MSDN which gives the following two solution:
1: Check the name of the member to ensure it is accurate.
2: Use an actual member of the class.
My button is named okButton and the method is okButton_Click(). The error is highlighted in the popup.g.i.vb file, saying that Me.okButton_Click is not a member of my popup class. I do not see how either of the fixes above apply, since I am using the correct name and the member does exist.
Your constructors are not defined correctly - constructors are always named New in VB.NET - and you need to call InitializeComponent from your constructor. You are also doing Dim errorMessage As TextBlock, which should not be required since it is defined in XAML.
It seems like something has broken the link between the XAML and the code behind file, and it's probably easier to delete all files related to the window and start from scratch, but your code behind should look something like this:
Partial Public Class popup
Inherits Window
Public Sub New()
' This call is required by the designer.
InitializeComponent()
End Sub
Public Sub New(ByVal message As String)
' This call is required by the designer.
InitializeComponent()
errorMessage.Text = message
End Sub
Private Sub okButton_Click(sender As Object, e As RoutedEventArgs)
Me.Close()
End Sub
End Class
In VS2015, the code behind does not have the Partial or Inherits Window parts, so those may not be required, but probably don't hurt anything.
Displaying the window should also look like the C# version:
Dim errorWindow As New popup("An error has occured.")
errorWindow.ShowDialog()

Wpf Application Startup appears to run twice

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

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

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