How to properly expose Windows form object to other classes - wpf

I have a basic question. I'm creating a VSTO Word Addin. I have a Ribbon button which opens a WPF dialog box called TableSelector. It is hosted in a Windows form.
Public Class RibbonControl
Private f As Form
Private Sub btnSelectTable_Click(sender As Object, e As RibbonControlEventArgs) Handles btnSelectTable.Click
Dim h As New System.Windows.Forms.Integration.ElementHost()
Dim tableselector1 As New TableSelector
f = New Form()
f.MaximumSize = New Size(500, 380)
f.MinimumSize = New Size(500, 380)
f.MaximizeBox = False
f.Name = "HostForm"
h.Dock = DockStyle.Fill
h.Child = tableselector1
f.Controls.Add(h)
f.Show()
f.TopMost = True
End Sub
Public ReadOnly Property hostForm() As Form
Get
Return f
End Get
End Property
End Class
Then I have a close button on that WPF control to close the dialog box. When I click it I get runtime error "Object reference not set to an instance of an object." on line 3 of the below code.
Private Sub btnClose_Click(sender As Object, e As RoutedEventArgs) Handles btnClose.Click
Dim ribbon As New RibbonControl()
ribbon.hostForm.Close()
End Sub
What am I missing?

You can use following code for get the specific window for close
Window win = Application.Current.Windows.OfType<Window>().SingleOrDefault(w => w.Name == "Window Name");
win.Close();

Related

What is the best way to update the source of a XamDataGrid from a different form?

I have a XamDataGrid in my MainWindow which has a Public Shared List(Of Artikelstammdaten) as DataSource. After opening a few other forms I want to add more data to the XamDataGrid with a button click. I thought the easiest way would be just to update the DataSource, but I get an Error:
The reference to an unreleased member requires an object reference.
This is what I have tried:
Private Sub Add_Click(sender As Object, e As RoutedEventArgs)
Dim update = MainWindow.listArtikelstammdaten.Concat(CType(Import.ComparedAccessData, IEnumerable(Of Artikelstammdaten)))
dgArticleMasterData.DataSource = update
Me.Close()
End Sub
If dgArticleMasterData is defined in the MainWindow class, you need to get a reference to the MainWindow instance to be able to access it.
You should be able to find it in the Application.Current.Windows collection:
Private Sub Add_Click(sender As Object, e As RoutedEventArgs)
Dim update = MainWindow.listArtikelstammdaten.Concat(CType(Import.ComparedAccessData, IEnumerable(Of Artikelstammdaten)))
Dim window = Application.Current.Windows.OfType(Of MainWindow).FirstOrDefault()
If window IsNot Nothing Then
window.dgArticleMasterData.DataSource = update
End If
Me.Close()
End Sub

wpf richtextbox in winforms application

I would like to use a WPF RichTextBox in a WinForms project written with VB
I have created the WinForms project with one form and a button
I then added a new project WPF User Control Library placed a WPF RichTextBox on the WPF form
I added ElementHost interoperability to the WinForm with these Imports
Imports System
Imports System.Windows.Forms
Imports System.Windows.Forms.Integration
From here I am lost some of the SO question are 10 to 7 years old the MS tutorial is not much help
Code from WPF Form
Public Class UserControl1
ReadOnly rtbWPF As New UserControl
ElementHost
wpfwindow.Show
End Class
I did not post the XAML code NOT sure how to do that
So the question what to do next to link the WPF form with the RTB to the WinForms form?
I would like to load data from a SQLite DB into the WPF RichTextBox and save the text entered in the RTB into the DB
This answer is meant to expand on #KyleWang wonderful answer
One BIG issue with Vectors choice of the WPF RichTextBox is There is no Text property in the WPF RichTextBox control. Here is one way to get all of the text out. That said I would IMHO would suggest using the WPF Plain TextBox control
Vector also commented on how to hide the HotReload in the title bar
Tools > Options > Debugging > General > un-check Enable UI Debugging Tools for XAML
OK Code Below hope this is helpful if you decide to use a WPF control in WinForms for spell checking
Public Class frmStart
Dim rtb As Windows.Controls.RichTextBox = New Windows.Controls.RichTextBox()
Dim tb As Windows.Controls.TextBox = New Windows.Controls.TextBox()
Dim str As String = " "
Private Sub frmStart_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ElementHost1.Child = rtb
rtb.SpellCheck.IsEnabled = True
ElementHost2.Child = tb
tb.SpellCheck.IsEnabled = True
If str.Length < 100 Then
rtb.VerticalScrollBarVisibility = Windows.Controls.ScrollBarVisibility.Visible
End If
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
str = "Plain WPF TxtBox"
tb.Text = str
rtb.AppendText("Heree is som mispelled txt se if the dictioary wrks more nonsense to see the scroll bar's will this word wrapp or is that rapp")
End Sub
Private Sub btnGet_Click(sender As Object, e As EventArgs) Handles btnGet.Click
Dim elementHost = ElementHost1
Dim wpfRichText = CType(elementHost.Child, Windows.Controls.RichTextBox)
Dim range As Windows.Documents.TextRange = New Windows.Documents.TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd)
Dim allText As String = range.Text
tbMsg.Text = allText.ToString
End Sub
Private Sub btnGTB_Click(sender As Object, e As EventArgs) Handles btnGTB.Click
Dim elementHost = ElementHost2
Dim text = tb.Text
tbMsg.Text = text.ToString
End Sub
To host a WPF control in Winforms, you can refer to the following two ways.
First, both of them need to add a ElementHost control into form.
Solution A:
Directly declare the wpf controls (using Windows.Controls)
Dim rtb As Windows.Controls.RichTextBox = New Windows.Controls.RichTextBox()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
rtb.SpellCheck.IsEnabled = True
ElementHost1.Child = rtb
End Sub
Solution B:
Create a new User Control(WPF) and edit the content in "UserControl1.xaml" as follows.
<Grid>
<RichTextBox x:Name="richtextbox" Foreground="Black" FontSize="24" Margin="0"></RichTextBox>
<RichTextBox SpellCheck.IsEnabled="True" />
</Grid>
Then modify the code in 'form1.vb'
Private uc As UserControl1 = New UserControl1()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ElementHost1.Child = uc
End Sub

ShowDialog Form property is empty

I have two of the simplest forms, with a couple of Buttons and a TextBox. I click to open the second form (frmModal) using ShowDialog(), type some text into txtGreeting and press the Yes button. What should happen is that a MessageBox appears confirming the text that was entered into txtGreeting, but it is empty.
I understand that the Form's properties should be accessible until the form goes out of scope, but they disappear straight-away. I can't even read dialog.txtGreeting.Text.
Am I missing anything obvious please?
Public Class frmMain
Private Sub btnModal_Click(sender As Object, e As EventArgs) Handles btnModal.Click
Dim dialog As frmModal
dialog = New frmModal()
Dim result As DialogResult = frmModal.ShowDialog(Me)
If result = Windows.Forms.DialogResult.Yes Then
MessageBox.Show(dialog.Greeting)
End If
'dialog.Dispose()
End Sub
End Class
Public Class frmModal
Public Property Greeting As String
Get
Return txtGreeting.Text
End Get
Set(value As String)
End Set
End Property
Private Sub btnYes_Click(sender As Object, e As EventArgs) Handles btnYes.Click
MessageBox.Show(Greeting)
End Sub
End Class
The Yes button has it's DialogResult property set to Yes.
I've tried moving the dialog-declaration out of the click-event, using an (unnecessary) Dispose(), deliberately assigning the Greeting property in the Yes-click event..
You're effectively instantiating the form twice. By showing frmModal with ShowDialog and then asking for the Greeting value on the instance you created, named 'dialog'.
This should fix it.
Private Sub ModalTestButton_Click(sender As System.Object, e As System.EventArgs) Handles ModalTestButton.Click
Dim dialog As frmModal
dialog = New frmModal()
Dim result As DialogResult = dialog.ShowDialog(Me)
If result = Windows.Forms.DialogResult.Yes Then
MessageBox.Show(dialog.Greeting)
End If
End Sub

Error with adding WPF user control to ElementHost in Windows Form

I am trying to add a WPF user control to windows form. The WPF user control currently does not have anything in it, but I will be adding buttons. In form load, I do this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Application.EnableVisualStyles()
Dim elemHost As New ElementHost
Dim wuc As WPFUC = New WPFUC
elemHost.Controls.Add(wuc) <<-- I get error here
'elemHost.child = wuc <<-- and here
AddSolid()
'AddPanel()
End Sub
Error is "Value of type WindowsApplication1.WPFUC cannot be converted to System.Windows.Forms.Control. What else should I do?
I just calculated the screen points using PointToScreen method and specify that as location of WPF window wherever I needed.

Cannot update a treeview inside a usercontrol

I created a usercontrol with a treeview inside it. The treeview will be populated if I add nodes in the onload handler of the usercontrol. But after that(for example, I click a button in its parent form), the treeview will not refresh. I can see the nodes was updated in memory, but it just cannot display on the screen. I called refresh/update after adding nodes. Any suggestion is appreciated.
I put a quick test together based on your description and it seems to paint just fine.
UserControl1
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class UserControl1
Inherits System.Windows.Forms.UserControl
'UserControl overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.TreeView1 = New System.Windows.Forms.TreeView
Me.SuspendLayout()
'
'TreeView1
'
Me.TreeView1.Dock = System.Windows.Forms.DockStyle.Fill
Me.TreeView1.Location = New System.Drawing.Point(0, 0)
Me.TreeView1.Name = "TreeView1"
Me.TreeView1.Size = New System.Drawing.Size(150, 150)
Me.TreeView1.TabIndex = 0
'
'UserControl1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.Controls.Add(Me.TreeView1)
Me.Name = "UserControl1"
Me.ResumeLayout(False)
End Sub
Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
End Class
Public Class UserControl1
Public Sub AddNewNode(ByVal text As System.String)
TreeView1.Nodes.Add(text)
End Sub
End Class
Put the usercontrol on a form with a button
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
UserControl11.AddNewNode(Now.ToString)
End Sub
End Class
If you are seeing proper painting as well then look at any graphics handling in the parent form then the usercontrol then the controls within the usercontrol. We really need more info.
Thank you, Dave. I figured it out. I put the usercontrol twice to my form by mistake(I cannot remember how I did it). And the one I operate is underneath the other one. That's why I cannot see it. Sorry for wasting your time.

Resources