Multi-Thread (Append Text To TextBox) - vb.net

Done my fair share of looking this up but it just doesn't make sense..
I know we have to use delegates to update a textbox thats on the Main UI.
Here is the code in the a nutshell:
Initiate the thread that will capture chats:
ChatQuery = New Thread(AddressOf FetchChats)
ChatQuery.Start()
FetchChats Code Simplified:
SetTextBoxWithInvoke(Form5.TextBox2, MESSAGE)
SetTextBoxWithInvokeCode:
Private Sub SetTextBoxWithInvoke(ByVal TB As TextBox, ByVal msg As String)
If TB.InvokeRequired Then
TB.Invoke(New AddToMessageBoxDelegate(AddressOf SetTextBoxWithInvoke), New Object() {TB, msg})
Else
TB.Text &= msg
End If
End Sub
The Problem?? Invoke is never required, and the new message is never appended to the textbox I need to be appended to.
Delegate:
Public Delegate Sub AddToMessageBoxDelegate(ByVal TB As TextBox, ByVal msg As String)

The problem is that you're using the default instance of the form here:
SetTextBoxWithInvoke(Form5.TextBox2, MESSAGE)
Default instances are thread-specific so, if you execute that code on a background thread, rather than using the existing Form5 instance that was created and displayed on the UI thread, it will create a new instance on the current thread. There's no need to invoke a delegate to access that instance so InvokeRequired is always False.
You need to use the actual instance of Form5 that already exists. How exactly you do that depends on the circumstances. If the code that makes the call is already in that form then just use Me, which is implicit if you don't explicitly use another reference anyway. Otherwise, it's up to you to get the required reference into the required object to be used.
If the code is not in a form already then maybe you should not be doing it that way at all. Instead, you can use the SynchronizationContext class. You get the current instance when your object is created on the UI thread and you can then call its Send or Post method to marshal back to the UI thread without an explicit Control reference. That might not work in your case though, because you'd still need a reference to the correct TextBox.

Related

ExpandoObject PropertyChanged event not triggering in propertygrid

Basically I am loading a JSON object that contains combinations of values available or not at run time, so I need to know when a specific property is modified to then toggle all the other browsable etc.. and though that the PropertyChange event was the perfect way to handle it.
So I can add an event handler to get triggered on my expandoobject like this:
Dim test As Object = new ExpandoObject
AddHandler CType(test, INotifyPropertyChanged).PropertyChanged, AddressOf expando_PropertyChanged
and the handler is as basic as it gets
Public Shared Sub expando_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
Debug.Print("Property {0} set or changed", e.PropertyName)
End Sub
so far this works, if I add or modify a property right after that, I get notified.
however if I return this and set it as the selectedobject of my propertygrid, I cannot get the event to trigger.
I'm using a custom PropertyDescriptor and ICustomTypeDescriptor to set a few other attributes for the propertygrid, so I assumed it might be as easy as setting the attribute
<RefreshProperties(RefreshProperties.All)>
but I cannot find a way to override the Refresh in the PropertyDescriptor unlike Browsable or readonly, which kinda makes sense as the property grid would need to know ahead of time that it needs to be refreshable.
So I could not make the INotifyPropertyChanged work with the expando, it would work with a dynamicObject where I would implement it myself but that was requiring too much of a rewrite for me.
I ended up add a lambda on my expando that I call on the PropertyDescriptor SetValue
CType(_expando, Object).toggleSwitches.Invoke(_expando, _name, value)
note the use of Invoke here in vb.net that was also a PITA but I found this guy who had the same issue as I did: https://github.com/dotnet/vblang/issues/226
It is not necessary to use invoke in C# and as 99% of the examples are in C# it took me more time than I wanted to implement it.
Hopefully this will help someone too.
here is the lambda if interested as well:
_expando.toggleSwitches = Sub(obj As Object, caller As String, value As Object)
Debug.Print(caller & " " & value.ToString())
End Sub

Convert VB.net Code into C#.net

I am working on a C#.net. I have a code of vb.net and I want to convert those code into C#.
I have done all my task but while running application it gives me a error of object not set to an object reference. below is my VB.net code. I have used third party ddl in my code so ExchangeList is a class of that dll.
Private WithEvents moExchanges As ExchangeList
Private Sub RequestChartData()
Trace.WriteLine("Init")
moExchanges = moHost.MarketData.Exchanges
End Sub
Now below is my C#.code
Private Host moHost;
Private ExchangeList moExchanges;
private void RequestChartData()
{
Trace.WriteLine("Init");
moExchanges = moHost.MarketData.Exchanges;
}
Thanks.
It's not possible to tell you with 100% certainty the source of your object not set to an object reference. without seeing more code, but the error appears to be telling you that moHost is null - in other words, you haven't created an instance of the object yet.
So when you try to call MarketData.Exchanges on the object (so you can assign it to moExchanges, it's throwing the error.
Find moHost in your code and make sure you have that you have assigned an instance of that object to it (by calling it's constructor, like moHost = new Host() or whatever the constructor is), and this should fix your error.
UPDATE
You never initialize moHost. This line:
private Host moHost;
Simply declares the object - at this point it's null. So when you try to access any instance methods/properties, you get the object not set to an object reference error.
You need to create an instance of moHost by calling it's constructor, something like this:
private Host moHost = new Host();
The constructor may require parameters - take a look at the documentation for the third-party DLL (intellisense in the IDE may also tell you what parameters, if any, are needed).
This will take care of your error.
()Instead of:
Private Host moHost;
Private ExchangeList moExchanges;
I think you need to write it as:
Private Host moHost = New Host();
Private ExchangeList moExchanges = New ExhangeList();

Why can my VB.NET User Control not instantiate an ObjectContext?

I have the following lines of code as a test user control. When the project is built, and I drag this user control onto a form, I get an error dialogue to the effect that EF can't find the connection string for the context. Yet when I use the same variable in a form, all is well. It seems the user control is using a different context within which to look for the connection string than the usual app.config.
Public Class InvoiceWorkOrderSearch
Private _dataHelper As WorkOrderData = New WorkOrderData()
End Class
During Design time?
You can avoid this be only instancing the object if the control is in runtime mode.
The build in property to check for desing time (Me.DesignMode) is poor since it only tells you if you are currently designing the control itself. It returs false if you drop the usercontrol on a form.
You can use this code to check for designtime: http://dotnet-snippets.de/dns/designmode-workaround-windows-forms-SID299.aspx
Public Class InvoiceWorkOrderSearch
Private _dataHelper As WorkOrderData
Public Sub New()
If IsDesignMode(me) = False Then
_dataHelper = New WorkOrderData()
End If
End Sub()
End Class

Threading: Call a delegate from a separate thread (VS2010)

So, I'm having troubles implementing a separate thread. This is because I have a simple class, and in it I start a new thread. So, as it is not any form, I haven't found any way to make it call the function in the UI Thread.
So, I cannot use the Invoke method. Is there any way to call a function from another thread?
I am going to assume that you have events exposed from your class and that you want the event handlers to execute on a UI thread. I suppose you could have a callback that the caller specifies as well. Either way the pattern I will describe below will work in both cases
One way to make this happen is to have your class accept an ISynchronizeInvoke instance. Form and Control instances implement this interface so a reference to one of them could be used. You could make it a convention that if the an instance is not specified then event handlers executed by raising events on your class would execute in the worker thread instead of the thread hosting the ISynchronizeInvoke instance (usually a form or control).
Public Class YourClass
Private m_SynchronizingObject As ISynchronizeInvoke = Nothing
Public Sub New(ByVal synchronizingObject As ISynchronizeInvoke)
m_SynchronizingObject = synchronizingObject
End Sub
Public Property SynchronizingObject As ISynchronizeInvoke
Get
Return m_SynchronizingObject
End Get
Set(ByVal value As ISynchronizeInvoke)
m_SynchronizingObject = value
End Set
End Property
Private Sub SomeMethodExecutingOnWorkerThread()
RaiseSomeEvent()
End
Private Sub RaiseSomeEvent()
If Not SychronizingObject Is Nothing AndAlso SynchronizingObject.InvokeRequired Then
SynchronizingObject.Invoke(New MethodInvoker(AddressOf RaiseSomeEvent)
End If
RaiseEvent SomeEvent
End Sub
End Class
The first thing to notice is that you do not have to specify a synchronizing object. That means you do not have to have a Form or Control reference. If one is not specified then SomeEvent will be raised on the worker thread. This is the same pattern that is used in the System.Timers.Timer class.
Try to expose some events in your class, fire them when you need to notify your UI and finally make your UI Component register to these events,
when the event is fired, the listener methods will be executed. there you can use Control.Invoke or Control.BeginInvoke to execute your code on the UI thread.

How to load a class into the current instance within Sub New

Long term lurker, first time poster here.
I have written a class to model an object in vb.net, using vs2008 and framework 2.0. I am serializing the class to an XML file for persistent storage. I do this with a method in the class like this:
Public Sub SaveAs(ByVal filename As String)
Dim writer As New Xml.Serialization.XmlSerializer(GetType(MyNamespace.MyClass))
Dim file As New System.IO.StreamWriter(filename)
writer.Serialize(file, Me)
file.Close()
End Sub
I now want to do a similar thing but reading the class from file to the current instance, like this:
Public Sub New(ByVal filename As String)
Dim reader = New Xml.Serialization.XmlSerializer(GetType(MyNamespace.MyClass))
Dim file = New System.IO.StreamReader(FullPath)
Me = CType(reader.Deserialize(file), MyNamespace.MyClass)
End Sub
However, I cannot assign anything to “Me”. I’ve tried creating a temporary object to hold the file contents then copying each property and field over to the current instance. I iterated over the properties (using Reflection), but this soon gets messy, dealing with ReadOnly collection properties, for example. If I just copy each property manually I will have to remember to modify the procedure whenever I add a property in the future, so that sounds like a recipe for disaster.
I know that I could just use a separate function outside the class but many built-in .NET classes can instantiate themselves from file e.g. Dim bmp As New Bitmap(filename As String) and this seems very intuitive to me.
So can anyone suggest how to load a class into the current instance in the Sub New procedure? Many thanks in advance for any advice.
I'd put a shared load function on the class, that returned the newly de-serialised object.
e.g.
Public Class MyClass
...
Public shared Function Load(ByVal filename As String) as MyClass
Dim reader = New Xml.Serialization.XmlSerializer(GetType(MyNamespace.MyClass))
Dim file = New System.IO.StreamReader(FullPath)
Return CType(reader.Deserialize(file), MyNamespace.MyClass)
End Sub
End Class
...
Dim mine as MyClass = MyClass.Load("MyObject.Xml");
Hope this helps
Alternatively,
Encapsulate the data of your class in an inner, private class.
The properties on your outer visible class delegate to the inner class.
Then Serialising and De-serialising happens on the inner class, you can then have a ctor that takes the file name, de-serialises the inner hidden object, and assigns it to the classes data store.
The "New" method in VB.Net is a constructor for the class. You can't call it for an existing instance, as the whole purpose of the method is to create new instances; it's just not how the language works. Try naming the method something like "ReadFrom" or "LoadFrom" instead.
Additionally, given those methods, I would try to implement them using a Factory Pattern. The ReadFrom method would be marked Shared and return the new instance. I would also make the method more generic. My main ReadFrom() method would accept an open textreader or xmlreader or even just a stream, rather than a file name. I would then have overloads that converts a file name into a stream for reading and calls the main method.
Of course, that assumes I use that pattern in the first place. .Net already has great support for xml serialization built into the platform. Look into the System.Xml.Serialization.XmlSerializer class and associated features.