How to implement a Windows Form in vb2008 in vb6 - winforms

I have written a Test-Form in vb2008 in order to call it as a mdi-child in vb6:
The code is as followed:
`
Imports System.Runtime.InteropServices
<ComClass(frmTest.ClassId, frmTest.InterfaceId, frmTest.EventsId)> _
Public Class frmTest
Inherits System.Windows.Forms.Form
#Region "COM-GUIDs"
Public Const ClassId As String = ""
Public Const InterfaceId As String = ""
Public Const EventsId As String = ""
#End Region
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Public Overloads Sub Show(ByVal MDI As Object)
Me.MdiParent = CType(MDI, System.Windows.Forms.Form)
Me.Show
End Sub
Public Sub SomeText(ByVal Text As String)
MsgBox(Text)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
MsgBox("Test")
End Sub
End Class
`
In vb6, under references I make a reference to the tlb.
So far, so good.
I open a new project and create a new MDI-Form.
Private Sub Start_Click(Index As Integer)
Dim f As New MyTestLibrary.frmTest
f.Show (Me)
End Sub
Unfortunately, this approach does not work, because it is COM-Component, and an error occurs. Anyone knows a verified way to make a windows .NET form available in VB6 ???
Thank you, in advance.
Stephan

Put your VB 6 in a DLL. Create a public method that invokes a modal dialog from VB 6.
From your .NET program, reference the DLL built in VB 6 (COM tab)
Invoke the method. Your VB6 modal form will appear.
However, some things may not work such as some ActiveX controls embedded in the VB 6 code might have problems.

Related

Config File cannot be saved for second instance WPF

I am having an issue saving the config file when working with two instances of my program. I was able to reproduce this issue in a simple example project that looks like that:
Class MainWindow
Dim config As System.Configuration.Configuration
Public Sub New()
config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None)
End Sub
Protected Overrides Sub OnClosing(e As CancelEventArgs)
config.Save(ConfigurationSaveMode.Modified, True)
End Sub
End Class
The first instance is saving the config on closing, but as soon as I am trying to close the second instance, config.Save(ConfigurationSaveMode.Modified, True) is throwing an error saying that the config file was changed by another program. I hope someone is able to help me with that problem. Thanks in advance.
edit: Forgot to delete the MyBase call
edit2: Tried Chillzy suggestion, but it fails as well.
Protected Overrides Sub OnClosing(e As CancelEventArgs)
Dim mdate As String = Date.Now.ToString("yyyyMMdd_HHmmss")
Dim mptpath As String = Path.GetDirectoryName(config.FilePath) & "\" & mdate
config.SaveAs(mdate, ConfigurationSaveMode.Full, True)
File.Delete(fpath)
File.Move(mptpath, fpath)
End Sub
There. You copy load the config file then save as. Re-Read the saveas file as the current config file. on your way out you do the reverse
Imports System.Configuration
Imports System.IO
Public Class Form1
Dim config As System.Configuration.Configuration
Dim fpath As String = ""
Dim mptpath As String = ""
Public Sub New()
config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None)
fpath = config.FilePath
Dim mdate As String = Date.Now.ToString("yyyyMMdd_HHmmss")
mptpath = Path.GetDirectoryName(config.FilePath) & "\" & mdate & ".config"
config.SaveAs(mptpath, ConfigurationSaveMode.Full, True)
config = System.Configuration.ConfigurationManager.OpenExeConfiguration(mptpath)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
File.Delete(fpath)
config.SaveAs(fpath, ConfigurationSaveMode.Full, True)
File.Delete(mptpath)
End Sub
End Class
You are making a loop by calling the OnClosing at the end of OnClosing
Protected Overrides Sub OnClosing(e As CancelEventArgs)
config.Save(ConfigurationSaveMode.Modified, True)
End Sub

Updating UI from another thread with VB in WPF

I am trying to use a timer to scan my Xbox 360 controller. But I cannot directly update my UI like the code I wrote below.
I would get a exception when I try to run this code.
An exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll but was not handled in user code
Additional information: The calling thread cannot access this object because a different thread owns it.
XButton is a radiobutton on the GUI that I want to toggle.
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
Imports System.Timers
Imports System.Windows.Threading
Public Class XboxControllerStatus
Friend WithEvents Timer1 As Timer
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Elapsed
Dim currentState As GamePadState = GamePad.GetState(PlayerIndex.One)
If currentState.IsConnected Then
If currentState.Buttons.X.Pressed Then
XButton.IsChecked = True
Else
XButton.IsChecked = False
End If
End If
End Sub
End Class
This works for me, all the time
Control.Invoke(sub()
'Put code here
End Sub)
First you need to set up a delegate
Delegate Sub SetCheckBoxCallback(ByVal value As Boolean)
Friend Sub SetCheckBox(ByVal value As Boolean)
XButton.IsChecked = value
End Sub
after that all you need to do is call the following code from within your timer to invoke it:
Dim DesiredValue as Boolean = True
Me.Dispatcher.Invoke(New SetCheckboxCallback(AddressOf SetCheckbox), New
Object() {DesiredValue})

Cannot print in VB2010 Windows Forms using Microsoft.VisualBasic.Compatibility.VB6

I am trying to print from VB2010 Windows Forms using the Microsoft.VisualBasic.Compatibility.VB6 library.
I have downloaded the library and imported it onto my form. The Microsoft help files are inaccurate and incomplete, and there is not a complete example. A simple form with a print button that prints "Hello World!" to the default system printer would be enough to get me started.
Thanking you in advance for any help offered...
Using the proper library will go a long end to making this simple. Use the PrintDocument class instead:
Imports System.Drawing.Printing
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim doc = New PrintDocument()
AddHandler doc.PrintPage, AddressOf PrintHello
doc.Print()
End Sub
Private Sub PrintHello(sender As Object, e As PrintPageEventArgs)
e.Graphics.DrawString("Hello world", Me.Font, Brushes.Black, New PointF(0, 0))
End Sub
End Class

Passing of variable value from one form another

im just wondering on how can i pass value of a variable to another form from a different form
I have a form called frmSearch then I have another form called frmMain from frmSearch i have a varible A which is publicly declared and i wanted the value of A to frmMain i've tried the following
frmMain
dim B = frmSearch.A
but everytime i checked the value of B it always returns a blank string
also when i checked the value of frmSearch.A it also returns nothing even though it returns a value when i checked it in frmSearch
please help im really stuck
thanks in advance
Accessing a field of a form shouldn't be a problem. Just make sure that at the time you are reading the field it is already assigned.
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim form = New Form2
Debug.Assert(form.A Is Nothing)
form.ShowDialog()
Debug.WriteLine(form.A(0))
End Sub
End Class
Public Class Form2
Public A As String()
Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
A = {"abc", "aaa"}
End Sub
End Class

DispatcherObject cast woes and Async / ObservableCollection issues in WPF

The code below pulls out a bunch of records from an Access 2010 database; hence rolling my own connector bits. I've succeeded in doing the observablecollection and made it all bind up with nice drag and drop data sources, from my own objects. However, like a daft person, I want to do this Asynchronously. Yet, I've got a small cast monster problem, and I don't know what to feed it! Can anyone advise me - I've tried a lot of reading around, but the concepts are just a little too many at once on a Friday afternoon and I'm struggling to make any real headway.
The line I'm having trouble with is:
Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject )
The exception is:
Unable to cast object of type '_Closure$__2[SomeRecord_Viewer.SomeRecord]' to type 'System.Windows.Threading.DispatcherObject'.
I've managed to make a WPF listbox populate via the code below, however only by commenting out a part of the ObservableCollectionEx class. This causes synchronisation problems and a crash after a few hundred records are entered.
Class that builds the threaded list of entities - in this case, an ObservableCollectionEx(Of SomeRecord):
Class SomeRecordSet
Inherits ObservableCollectionEx( Of SomeRecord)
Private Shared Property _SomeRecordList As New ObservableCollectionEx(Of SomeRecord )
Public Shared ReadOnly Property SomeRecordList As ObservableCollectionEx(Of SomeRecord )
Get
If _SomeRecordList.Count = 0 Then BuildSomeRecordListAsync()
Return _SomeRecordList
End Get
End Property
Public Shared ReadOnly Property ReturnSingleSomeRecord(id As Integer) As SomeRecord
Get
Return ( From SomeRecord In _SomeRecordList Where SomeRecord.id = id Select SomeRecord).First()
End Get
End Property
Private Shared Async Sub BuildSomeRecordListAsync()
Await Task.Run( Sub() BuildSomeRecordList())
Return
End Sub
Private Shared Sub BuildSomeRecordList()
Db.newcmd( "Select * from RecordList ")
While Db.read
Dim SomeRecord As New SomeRecord
With SomeRecord
.id = Db.dbint( "ID")
.type = Db.dbin( "type")
End With
_SomeRecordList.Add(SomeRecord)
End While
End Sub`
Partial code for the SomeRecord class:
Class SomeRecord
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged( ByVal info As String)
RaiseEvent PropertyChanged(Me , New PropertyChangedEventArgs (info))
End Sub
...'lots of simple properties.
End Class
The threaded collection class code - translated from another online source.
'I use PostSharp for try catch stuff.
`
Public Class ObservableCollectionEx (Of T )
Inherits ObservableCollection( Of T)
' Override the event so this class can access it
Public Shadows Event CollectionChanged As System.Collections.Specialized.NotifyCollectionChangedEventHandler
Protected Overrides Sub OnCollectionChanged( ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs )
Using BlockReentrancy()
Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = Sub () RaiseEvent CollectionChanged(Me , e)
If (eventHandler Is Nothing) Then Return
Dim delegates() As [Delegate] = eventHandler.GetInvocationList
*******If I comment this out I can populate the Listbox via a CollectionView, however it dies with issues to do with the list not staying synchronised :).
'Walk thru invocation list
For Each handler As System.Collections.Specialized.NotifyCollectionChangedEventHandler In delegates
Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject)
' If the subscriber is a DispatcherObject and different thread
If (( Not (dispatcherObject) Is Nothing) AndAlso (dispatcherObject.CheckAccess = False )) Then
' Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority .DataBind, handler, Me, e)
Else
handler( Me, e)
End If
Next
*******End of stuff I comment out to get working partially***
End Using
End Sub
End Class
From what I can see, you have two problems.
You're assigning the local variable eventHandler to an anonymous method, rather than the actual event handler. It should be:
Dim eventHandler As NotifyCollectionChangedEventHandler = CollectionChangedEvent
NB: You need to use CollectionChangedEvent in VB, not CollectionChanged.
You're using CType to cast the target to a DispatcherObject, which won't work if the target isn't a DispatcherObject. Use TryCast instead:
Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
You can also tidy up the test on the next line by using IsNot:
If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
WARNING - The code below acts differently to the C# version. The key difference seems to be that in VB you can't Override an Event (Why on earth not?) yet in C# you can.
The result is the Handler is Nothing in VB but not in C# :(.
So the syntax builds without error but the VB version doesn't ever do anything.
Redone with the updated answer in VB. Thank you!
Note I cannot make this work with Entity Framework, yet. But I think that a me and EF issue, not the collection.
The code itself is here for anyone interested. My list DOES populate perfectly fine now. However, I would take this answer of mine with a small pinch of salt until I update saying how I've extensively tested perhaps :)
However the omens are good - here is the original C# author's site: Original Site
Public Class ObservableCollectionEx(Of T)
Inherits ObservableCollection(Of T)
'Override the event so this class can access it
Public Shadows Event CollectionChanged As NotifyCollectionChangedEventHandler
Protected Overrides Sub OnCollectionChanged(ByVal e As NotifyCollectionChangedEventArgs)
Using BlockReentrancy()
Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = CollectionChangedEvent
If eventHandler Is Nothing Then
Return
End If
Dim delegates() As [Delegate] = CollectionChangedEvent.GetInvocationList
'Walk thru invocation list
For Each handler As NotifyCollectionChangedEventHandler In delegates
Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
' If the subscriber is a DispatcherObject and different thread
If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
' Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, Me, e)
Else
handler(Me, e)
End If
Next
End Using
End Sub
End Class

Resources