Cannot dynamically add new button - wpf

I'm just starting to learn VB and Visual Studio and I've run across a problem. I've spent the best part of a day trying to find the answer and I have a horrible feeling that it's going to be something very simple that I've over looked.
I'm working on a WPF in Visual Studio 2010 and am trying to dynamically create a button on the main window when a button is clicked (I know, everything I've read tells me this is pretty basic!) Here's an edited snippet of the code I've written:
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports Excel = Microsoft.Office.Interop.Excel
Class MainWindow
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles edit.Click
...
Dim newButton As New Button
newButton.Text = "New Button"
newButton.Top = 200
newButton.Left = 20
Me.Controls.Add(newButton)
...
End Sub
To my eyes, this looks perfectly simple and correct, but I'm getting an error:
"'Controls' is not a member of 'myApp.MainWindow'."
Has anybody come across this before or know what the problem is? Apologies if this does turn out to be a simple fix :)

The error you are getting is telling you that Controls does not exist within MainWindow. Basically, there is not property by that name accessible from your event handler. If you are working with WPF and MainWindow inherits Window, then you need to set something within the Content property.
The best way to go about this, would be to have some form of container control as the content of the window. You can define this in XAML or in code (via code you should set the Window.Content property). Then, you can add more controls to that container. Suggested containers are Grid, Canvas and StackPanel, etc.
I would suggest something like this:
XAML
<MainWindow ...>
<StackPanel x:Name="ControlContainer">
<Button Content="Click me to create buttons!" Click="CreateButton_Click" />
</StackPanel>
</MainWindow>
Code Behind
Private Sub CreateButton_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim button As New Button()
' Initialize the button
' ...
' Add the button to the stack panel
Me.ControlContainer.Children.Add(button)
End Sub

well MainWindow is not a form. create a new project and copy the same code in a button it will work.
you must find out what is the problem with your form control.

It looks like you are mixing WinForms and WPF coding - these are two different technologies.
This link may help you to add a button at runtime in WPF

Related

How to write out button event without using WPF controls?

I do not know how to specify in the title, this is in WPF visual basic. I want to know how do I write a code so that when a button is clicked, the tabcontrol selection will be = 1
Here is what I have in my MainWindow, RightWindowCommands:
<Button Content="Information" Cursor="Hand" Click="InformationButton_OnClick"
ToolTip="View the information"
x:Name="InformationView"/>
However, I did not use the WPF tools' Button, as this is a GUI that I have to place the button at RightWindowCommands, I want to know how to come out with the code so that InformationButton_OnClick gives me tabControl.SelectedIndex = 1. Please guide me on writing this code out
Here is a nice example for onclick event handling a picture, you can change it to a number instead of picture.
`AddHandler pic.Click, AddressOf pic_Click'
Private Sub pic_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim pic As PictureBox = DirectCast(sender, PictureBox)
' etc...
End Sub
Source : add on click event to picturebox vb.net

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

How can I force a TabItem to initialize content on load?

[disclaimer: I am new to Visual Basic.]
In a WPF, I have a TabControl containing 2 TabItems:
The first TabItem contains a bunch of URLs.
The second TabItem consists of a DockPanel that contains a cefSharp webView (chromium embedded for .net)
When I click on a url in tab1 it loads a page in the browser contained in tab2... But, it only works if I have initialized the browser first by clicking on tab2.
After doing some searching, it looks like vb.net doesn't initialize the content in a TabItem until it becomes visible. (right?)
So, my question is, how can I force a non-selected tab to initialize its content on load, in the background? (ie. so I don't have to click on the tab or switch to it first)
EDIT:
As requested, here is the relevant code:
The relevant XAML consists of a single DockPanel named "mainBox"
<DockPanel Name="mainBox" Width="Auto" Height="Auto" Background="#afe0ff" />
And here is my "code behind" vb script:
Class MainWindow : Implements ILifeSpanHandler, IRequestHandler
Shared web_view1 As CefSharp.Wpf.WebView
Shared web_view2 As CefSharp.Wpf.WebView
Public Sub init(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Loaded
'This is in a DockPanel created on the xaml named mainBox
' set up tabControl:
Dim browserTabs As New TabControl()
browserTabs.BorderThickness = Nothing
Dim tab1 As New TabItem()
tab1.Header = "My Tab"
Dim tab2 As New TabItem()
tab2.Header = "Browser"
Dim tab1Content As New DockPanel()
Dim tab2Content As New DockPanel()
tab1.Content = tab1Content
tab2.Content = tab2Content
browserTabs.Items.Add(tab1)
browserTabs.Items.Add(tab2)
mainBox.Children.Add(browserTabs)
' set up browsers:
Dim settings As New CefSharp.Settings()
settings.PackLoadingDisabled = True
If CEF.Initialize(settings) Then
web_view1 = New CefSharp.Wpf.WebView()
web_view1.Name = "myTabPage"
web_view1.Address = "http://stackoverflow.com/"
web_view2 = New CefSharp.Wpf.WebView()
web_view2.Name = "browserPage"
web_view2.Address = "https://www.google.com"
web_view2.LifeSpanHandler = Me
web_view2.RequestHandler = Me
AddHandler web_view2.PropertyChanged, AddressOf web2PropChanged
tab1Content.Children.Add(web_view1)
tab2Content.Children.Add(web_view2)
End If
End Sub
End Class
So, in its default state, tab1 is showing at start up -- the browser on tab2 (web_view2) won't initialize until I click its tab or change to its tab via script. Hope this clears it up a bit.
Your code doesn't use Windows Forms' TabPage but perhaps this might still help
As we know, Controls contained in a TabPage are not created until the
tab page is shown, and any data bindings in these controls are not
activated until the tab page is shown. This is by design and you can
call TabPage.Show() method one by one as a workaround.
via MSDN forums
Also, based on the above idea, have you tried the following.
tab2.isEnabled = True
tab1.isEnabled = True
Or:
tab2.Visibility = True
tab1.Visibility = True
Also, the BeginInit Method might help in your situation.
I had the same problem but found it initializes if I use the name of the tabpage and show (tabName1.show()) on the form load code for each page ending with the one I want displayed:
tabPage2.show()
tabPage3.show()
tabPage4.show()
tabPage5.show()
tabPage1.show()
It ripples thru and you never see the pages changing but it works. The other suggestions didn't work for me in Visual Studio 2010.

WPF and VB.net: Data Binding to Separate Class created outside of Expression Blend

I have a WPF application with form that has a textbox named "txtStatusWindow". I also have a vb.net class handed to me by a co-worker that needs to be called and executed by the code in my application code-behind. My co-worker insists that I will need to use common .net events to update the textbox on my form.
The separate vb.net class:
Public Class globalclass
Public Event txtStatusWindow(ByVal Text As String)
Public Sub InitializeProgram()
RaiseEvent txtStatusWindow("Updating something.")
System.Threading.Thread.Sleep(2000)
RaiseEvent txtStatusWindow("Updating something else.")
System.Threading.Thread.Sleep(2000)
RaiseEvent txtStatusWindow("Updating something other than else.")
System.Threading.Thread.Sleep(2000)
RaiseEvent txtStatusWindow("Updating something other than the else stuff.")
System.Threading.Thread.Sleep(2000)
End Sub
End Class
I need to be able to call the sub "InitializeProgram()" from my code-behind, and it needs to be able to update "txtStatusWindow.text" as it runs.
I told him that the updating of the text box can be done with data-binding, but I don't know how to integrate a separate class like this into my project, how to call methods in it, or how to cause it to update my text blocks through data binding.
I also suggested that the methods in this class aren't optimal for connecting to the WPF project anyway, but he just wrote it as an example to discover how to connect the two projects.
Eventually, I will need to integrate classes like these that will be running separate threads to update their data from a dynamic source, and cause many controls to update in my application.
So far, the only way we have been able to get this to work from my code-behind is this:
Partial Public Class SplashScreen
Dim NewText as String
Public WithEvents Globals As globalclass = New globalclass
Public Delegate Sub StringDelegate(ByVal Text As String)
Public SplashText As String
Public Sub New()
MyBase.New()
Me.InitializeComponent()
Me.Show()
Globals.InitializeProgram()
End Sub
Public Sub UpdateSplashscreenHandler(ByVal Text As String) Handles Globals.UpdateSplashScreen
StatusWindowText.Text = Text
End Sub
Notwithstanding the fact that the WPF screen "freezes" until the "globalclass InitializeProgram" method completes (txtStatusWindow.Text does not update while sub without using the esoteric "refresh" extension...), I fully believe we are going about this the wrong way.
There are precious few examples out there concerning the integration and then binding to objects in existing code. Thanks for examining our little quandary.
If this status window is in XAML and the status window is a UserControl, then add a StatusText dependency property to the status window. Then, in the XAML you can bind to the value of that property with something like:
<UserControl x:Name="MyStatusWindow" ...>
<TextBlock Text="{Binding Path=StatusText, ElementName=MyStatusWindow}" />
</UserControl>
Then, from your event, just update the value of that StatusText property.
(Is that even close to what you were asking?)
Also, about that freezing: Instead of doing that updating in the constructor of that class, you might want to do it from the Loaded event of that control. It will still be freezing, though, unless you move it to a separate thread. Right now, that's happening on the same thread that the UI message pump is running on. This is the Dispatcher for that UI.

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