Mvvm. Textbox never change with System.Threading.Thread.Sleep - vb.net

I want change a textbox value, but this code doesn't work. I see only the last value.
If you want to help me copy and paste the code .
Thanks a lot
This is XAML
<TextBox HorizontalAlignment="Left" Height="46"
Margin="4,4,4,4" VerticalAlignment="Top" Width="162"
Text="{Binding Path=Msg,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
This is VB code.
Imports System.Threading
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System
Class MainWindow
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim x As New Abc
Me.DataContext = x
End Sub
End Class
Public Class Abc
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub OnPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Protected Sub OnNotifyPropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private Property _Msg As String
Public Property Msg As String
Get
Return _Msg
End Get
Set(value As String)
_Msg = value
OnPropertyChanged("Msg")
End Set
End Property
Private m_ButtonCommand As ICommand
Public Property ButtonCommand() As ICommand
Get
Return m_ButtonCommand
End Get
Set(value As ICommand)
m_ButtonCommand = value
End Set
End Property
Public Sub displayMessage(ByVal param As Object)
Msg = "How"
System.Threading.Thread.Sleep(1000)
Msg = "Are"
System.Threading.Thread.Sleep(1000)
Msg = "you"
System.Threading.Thread.Sleep(1000)
Msg = "?"
System.Threading.Thread.Sleep(1000)
End Sub
Private Function CandisplayMessage(ByVal param As Object) As Boolean
Return True
End Function
Public Sub New()
m_ButtonCommand = New DelegateCommand(AddressOf displayMessage, AddressOf CandisplayMessage)
End Sub
End Class
Public Class DelegateCommand
Implements ICommand
Private m_canExecute As Func(Of Object, Boolean)
Private m_executeAction As Action(Of Object)
Private m_canExecuteCache As Boolean
Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements ICommand.CanExecuteChanged
Public Sub New(ByVal executeAction As Action(Of Object), ByVal canExecute As Func(Of Object, Boolean))
Me.m_executeAction = executeAction
Me.m_canExecute = canExecute
End Sub
Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
Dim temp As Boolean = m_canExecute(parameter)
If m_canExecuteCache <> temp Then
m_canExecuteCache = temp
RaiseEvent CanExecuteChanged(Me, New EventArgs())
End If
Return m_canExecuteCache
End Function
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
m_executeAction(parameter)
End Sub
End Class
.............................................

When you use Thread.Sleep on UI Thread you block the UI thread, So nothing can happen in UI. If you want to show a 1 second wait after each message you have two choices.
1 - Using the Delay command in an Async method. https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-4
2 - Using a dispatcher frame, which can let the dispatcher work while your method waits. http://www.codeproject.com/Articles/152137/DispatcherFrame-Look-in-Depth
Unfortunately I'm not a VB programmer, But the code in c# would be like this.
Async Sample:
public Task displayMessage(object param){
Msg = "How";
await Task.Delay(1000);
Msg = "Are";
await Task.Delay(1000);
Msg = "you";
await Task.Delay(1000);
Msg = "?";
await Task.Delay(1000);
}
DispatcherFrame sample:
public void displayMessage(object param){
Msg = "How";
Wait(1000);
Msg = "Are";
Wait(1000);
Msg = "you";
Wait(1000);
Msg = "?";
Wait(1000);
}
public void Wait(int sleep)
{
var dFrame = new DispatcherFrame();
ThreadPool.QueueUserWorkItem(state => {
Thread.Sleep(sleep);
dFrame.Continue = false;
});
Dispatcher.PushFrame(dFrame);
}

Related

System.Timers.Timer and DataBinding

If I have a class that implements INotifyPropertyChanged, and I have a property in that class that is bound to a label on a form, how do I avoid a Cross-threaded exception if I set the property value from a System.Timers.Timer.Elapsed event handler?
The following code demonstrates the exception.
Imports System.ComponentModel
Imports System.Timers
Public Class Form1
Private thisClass As New aClass
Private WithEvents tmr As New System.Timers.Timer()
Private lbl As System.Windows.Forms.Label
Public Sub New()
InitializeComponent()
'create the label and add it to the form
lbl = New Label
lbl.Text = "some text"
Me.Controls.Add(lbl)
'set the data binding and start a timer
lbl.DataBindings.Add("Text", thisClass, "X")
tmr.Interval = 1000
AddHandler tmr.Elapsed, AddressOf tmr_Elapsed
tmr.Start()
End Sub
Private Sub tmr_Elapsed(sender As Object, e As ElapsedEventArgs)
'change the property value when the timer elapses
thisClass.X = Guid.NewGuid.ToString
End Sub
End Class
Public Class aClass
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _x As String = ""
Public Property X As String
Get
Return _x
End Get
Set(value As String)
_x = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("X"))
End Set
End Property
End Class
Alternative approach could be to use an asynchronous method to keep updating code on same thread.
Public Class MyForm
Private _viewmodel As MyViewModel
Private _intervalTask As Task
Private _canContinueIntervalRunning As Boolean
Public Sub New()
InitializeComponent()
_viewmodel = New MyViewModel()
CreateLabel() ' Create label and bind to viewmodel property
' Start interval without blocking this code execution
' Later we can use this saved task to make sure that task is complete
_canContinueIntervalRunning = True
_intervalTask = StartInterval()
End Sub
Private Async Function StartInterval() As Task
While _canContinueIntervalRunning
Await Task.Delay(1000)
_viewmodel.X = Guid.NewGuid().ToString()
End While
End Function
Private Async Sub FormClosing(sender as Object, e as FormClosingEventArgs) Handles MyForm.FormClosing
' Set "flag" to false and wait for task to complete
_canContinueIntervalRunning = False
Await _intervalTask
End Sub
End Class
With Await Task.Delay(1000) next line will be executed on same thread, which allows to update form controls without extra effort.
This is simple approach with boolean flag, another way of doing it would be to use cancellation token which you can pass to Task.Delay - then form don't need to wait for extra second, but can cancel Delay straight away.

How to create zip:// protocol in GeckoFx to read password protected zip files?

I'm create a program in VB.NET with embedded GeckoFx browser. How to creating zip:// protocol to read from password protected zip file?
Example: zip:///d:/dir/file.zip!/idnex.html
Note: jar:file:///d:/dir/file.zip!/idnex.html is not read the index.html from password protected ZIP file.
Initialize Gecko in MainWindow class:
Sub New()
InitializeComponent()
Xpcom.Initialize("Firefox64")
Xpcom.RegisterFactory(
New Guid("66170430-e4ec-11e9-aaef-0800200c9a66"),
"Zip protocol handler",
"#mozilla.org/network/protocol;1?name=zip",
New ZipFacrory)
End Sub
The ZipFactory class:
Class ZipFacrory
Implements nsIFactory
Public Function CreateInstance(aOuter As nsISupports, ByRef iid As Guid) As IntPtr Implements nsIFactory.CreateInstance
Return Marshal.GetComInterfaceForObject(New ZipProtocolHandler(), GetType(nsIProtocolHandler))
End Function
Public Sub LockFactory(lock As Boolean) Implements nsIFactory.LockFactory
End Sub
End Class
The ZipProtocolHandler class:
Class ZipProtocolHandler
Implements nsIProtocolHandler
Public Sub GetSchemeAttribute(aScheme As nsACStringBase) Implements nsIProtocolHandler.GetSchemeAttribute
aScheme.SetData("zip")
End Sub
Public Function GetDefaultPortAttribute() As Integer Implements nsIProtocolHandler.GetDefaultPortAttribute
Return -1
End Function
Public Function GetProtocolFlagsAttribute() As UInteger Implements nsIProtocolHandler.GetProtocolFlagsAttribute
Return nsIProtocolHandlerConsts.URI_NOAUTH Or nsIProtocolHandlerConsts.URI_IS_LOCAL_FILE Or
nsIProtocolHandlerConsts.URI_IS_LOCAL_RESOURCE
End Function
Public Function NewURI(aSpec As nsAUTF8StringBase, aOriginCharset As String, aBaseURI As nsIURI) As nsIURI Implements nsIProtocolHandler.NewURI
Dim mutator As nsIStandardURLMutator = Xpcom.CreateInstance(Of nsIStandardURLMutator)("#mozilla.org/network/standard-url-mutator;1")
Return mutator.Init(nsIStandardURLConsts.URLTYPE_STANDARD, -1, aSpec, aOriginCharset, aBaseURI).Finalize()
End Function
Public Function NewChannel2(aURI As nsIURI, aLoadinfo As nsILoadInfo) As nsIChannel Implements nsIProtocolHandler.NewChannel2
Return New ZipChannel(aURI, aLoadinfo)
End Function
Public Function NewChannel(aURI As nsIURI) As nsIChannel Implements nsIProtocolHandler.NewChannel
Return NewChannel2(aURI, Nothing)
End Function
Public Function AllowPort(port As Integer, scheme As String) As Boolean Implements nsIProtocolHandler.AllowPort
Return False
End Function
End Class
The ZipChannel class:
Class ZipChannel
Implements nsIChannel
Private status As Integer
Private loadGroup As nsILoadGroup
Private loadFlags As UInteger
Private originalURI As nsIURI
Private owner As nsISupports
Private notificationCallbacks As nsIInterfaceRequestor
Private contentType As String
Private contentCharset As String
Private loadInfo As nsILoadInfo
Private contentLengt As Long
Private contentDisposition As UInteger
Private contentDispositionFilename As Integer
Sub New(aURI As nsIURI, aloadInfo As nsILoadInfo)
originalURI = aURI
loadInfo = aloadInfo
End Sub
Public Sub GetNameAttribute(aName As nsAUTF8StringBase) Implements nsIChannel.GetNameAttribute, nsIRequest.GetNameAttribute
aName.SetData("Zip channel")
End Sub
Public Function IsPending() As Boolean Implements nsIChannel.IsPending, nsIRequest.IsPending
Return False
End Function
Public Function GetStatusAttribute() As Integer Implements nsIChannel.GetStatusAttribute, nsIRequest.GetStatusAttribute
Return status
End Function
Public Sub Cancel(aStatus As Integer) Implements nsIChannel.Cancel, nsIRequest.Cancel
status = aStatus
End Sub
Public Sub Suspend() Implements nsIChannel.Suspend, nsIRequest.Suspend
status = GeckoError.NS_OK
End Sub
Public Sub [Resume]() Implements nsIChannel.Resume, nsIRequest.Resume
status = GeckoError.NS_OK
End Sub
Public Function GetLoadGroupAttribute() As nsILoadGroup Implements nsIChannel.GetLoadGroupAttribute, nsIRequest.GetLoadGroupAttribute
Return loadGroup
End Function
Public Sub SetLoadGroupAttribute(aLoadGroup As nsILoadGroup) Implements nsIChannel.SetLoadGroupAttribute, nsIRequest.SetLoadGroupAttribute
loadGroup = aLoadGroup
End Sub
Public Function GetLoadFlagsAttribute() As UInteger Implements nsIChannel.GetLoadFlagsAttribute, nsIRequest.GetLoadFlagsAttribute
Return loadFlags
End Function
Public Sub SetLoadFlagsAttribute(aLoadFlags As UInteger) Implements nsIChannel.SetLoadFlagsAttribute, nsIRequest.SetLoadFlagsAttribute
loadFlags = aLoadFlags
End Sub
Public Function GetOriginalURIAttribute() As nsIURI Implements nsIChannel.GetOriginalURIAttribute
Return originalURI
End Function
Public Sub SetOriginalURIAttribute(aOriginalURI As nsIURI) Implements nsIChannel.SetOriginalURIAttribute
originalURI = aOriginalURI
End Sub
Public Function GetURIAttribute() As nsIURI Implements nsIChannel.GetURIAttribute
Return originalURI
End Function
Public Function GetOwnerAttribute() As nsISupports Implements nsIChannel.GetOwnerAttribute
Return owner
End Function
Public Sub SetOwnerAttribute(aOwner As nsISupports) Implements nsIChannel.SetOwnerAttribute
owner = aOwner
End Sub
Public Function GetNotificationCallbacksAttribute() As nsIInterfaceRequestor Implements nsIChannel.GetNotificationCallbacksAttribute
Return notificationCallbacks
End Function
Public Sub SetNotificationCallbacksAttribute(aNotificationCallbacks As nsIInterfaceRequestor) Implements nsIChannel.SetNotificationCallbacksAttribute
notificationCallbacks = aNotificationCallbacks
End Sub
Public Function GetSecurityInfoAttribute() As nsISupports Implements nsIChannel.GetSecurityInfoAttribute
'???
Return Nothing
End Function
Public Sub GetContentTypeAttribute(aContentType As nsACStringBase) Implements nsIChannel.GetContentTypeAttribute
aContentType.SetData(contentType)
End Sub
Public Sub SetContentTypeAttribute(aContentType As nsACStringBase) Implements nsIChannel.SetContentTypeAttribute
contentType = aContentType.ToString
End Sub
Public Sub GetContentCharsetAttribute(aContentCharset As nsACStringBase) Implements nsIChannel.GetContentCharsetAttribute
aContentCharset.SetData(contentCharset)
End Sub
Public Sub SetContentCharsetAttribute(aContentCharset As nsACStringBase) Implements nsIChannel.SetContentCharsetAttribute
contentCharset = aContentCharset.ToString
End Sub
Public Function GetContentLengthAttribute() As Long Implements nsIChannel.GetContentLengthAttribute
Return contentLengt
End Function
Public Sub SetContentLengthAttribute(aContentLength As Long) Implements nsIChannel.SetContentLengthAttribute
contentLengt = aContentLength
End Sub
Public Function Open() As nsIInputStream Implements nsIChannel.Open
'NS_ERROR_IN_PROGRESS (if the channel is reopened)
Throw New NotImplementedException()
End Function
Public Function Open2() As nsIInputStream Implements nsIChannel.Open2
Throw New NotImplementedException()
End Function
Public Sub AsyncOpen(aListener As nsIStreamListener, aContext As nsISupports) Implements nsIChannel.AsyncOpen
'example zip://impera.zip!/folder/file.png
Dim uri As Uri = originalURI.ToUri
Dim filespec As String = uri.Authority & uri.AbsolutePath
Dim t As String() = filespec.Split({"!/", "!\", "!"}, StringSplitOptions.None)
' MIME type
Dim ms = Xpcom.CreateInstance(Of nsIMIMEService)("#mozilla.org/mime;1")
Dim mime As nsACString = New nsACString
ms.GetTypeFromURI(originalURI, mime)
SetContentTypeAttribute(mime)
contentCharset = Text.Encoding.Default.WebName
aListener.OnStartRequest(Me, aContext)
Try
Using zip As ZipFile = New ZipFile(t(0))
Using zipstream As System.IO.Stream = zip(t(1)).OpenReader(kulcs), sr As System.IO.StreamReader = New System.IO.StreamReader(zipstream, Text.Encoding.Default)
Dim data As String = sr.ReadToEnd
Dim s = New nsAString
s.SetData(data)
Dim converter = Xpcom.CreateInstance(Of nsIConverterOutputStream)("#mozilla.org/intl/converter-output-stream;1")
Dim size As UInteger = zipstream.Length
Dim storagestream = Xpcom.CreateInstance(Of nsIStorageStream)("#mozilla.org/storagestream;1")
storagestream.Init(8192, size)
converter.Init(storagestream.GetOutputStream(0), Text.Encoding.Default.WebName) 'UTF-8 Text.Encoding.Default.BodyName
converter.WriteString(s)
converter.Close()
Dim stream = storagestream.NewInputStream(0)
aListener.OnDataAvailable(Me, aContext, stream, 0, stream.Available)
End Using
End Using
Catch ex As Exception
End Try
aListener.OnStopRequest(Me, aContext, GeckoError.NS_OK)
End Sub
Public Sub AsyncOpen2(aListener As nsIStreamListener) Implements nsIChannel.AsyncOpen2
AsyncOpen(aListener, Nothing)
End Sub
Public Function GetContentDispositionAttribute() As UInteger Implements nsIChannel.GetContentDispositionAttribute
Return contentDisposition
End Function
Public Sub SetContentDispositionAttribute(aContentDisposition As UInteger) Implements nsIChannel.SetContentDispositionAttribute
contentDisposition = aContentDisposition
End Sub
Public Sub GetContentDispositionFilenameAttribute(aContentDispositionFilename As nsAStringBase) Implements nsIChannel.GetContentDispositionFilenameAttribute
aContentDispositionFilename.SetData(contentDispositionFilename)
End Sub
Public Sub SetContentDispositionFilenameAttribute(aContentDispositionFilename As nsAStringBase) Implements nsIChannel.SetContentDispositionFilenameAttribute
contentDispositionFilename = aContentDispositionFilename.ToString
End Sub
Public Sub GetContentDispositionHeaderAttribute(aContentDispositionHeader As nsACStringBase) Implements nsIChannel.GetContentDispositionHeaderAttribute
'???
'aContentDispositionHeader.SetData("inline")
'aContentDispositionHeader.SetData("Content-Disposition: inline")
End Sub
Public Function GetLoadInfoAttribute() As nsILoadInfo Implements nsIChannel.GetLoadInfoAttribute
Return loadInfo
End Function
Public Sub SetLoadInfoAttribute(aLoadInfo As nsILoadInfo) Implements nsIChannel.SetLoadInfoAttribute
loadInfo = aLoadInfo
End Sub
Public Function GetIsDocumentAttribute() As Boolean Implements nsIChannel.GetIsDocumentAttribute
Return False
End Function
End Class
Test HTML page (D:/index.html):
<!DOCTYPE html>
<html>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
<p><img src="zip:///d:/web.zip!/truck.png"/><img src="truck.png"/></p>
</body>
</html>
The image does not load from the web.zip file.
But the channel works:
Dim uri = IOService.CreateNsIUri("zip:///d:/web.zip!/truck.png")
Dim ch As nsIChannel = IOService.NewChannelFromUri(uri)
Dim list = New Listener
ch.AsyncOpen(list, Nothing)
The Listener class:
Class Listener
Implements nsIStreamListener
Public Sub OnStartRequest(aRequest As nsIRequest, aContext As nsISupports) Implements nsIStreamListener.OnStartRequest
End Sub
Public Sub OnStopRequest(aRequest As nsIRequest, aContext As nsISupports, aStatusCode As Integer) Implements nsIStreamListener.OnStopRequest
End Sub
Public Sub OnDataAvailable(aRequest As nsIRequest, aContext As nsISupports, aInputStream As nsIInputStream, aOffset As ULong, aCount As UInteger) Implements nsIStreamListener.OnDataAvailable
Try
Dim ss = Gecko.IO.InputStream.Create(aInputStream)
Dim fs = System.IO.File.Create("d:\truck2.png")
ss.CopyTo(fs)
fs.Close()
Catch ex As Exception
End Try
End Sub
Private Sub nsIRequestObserver_OnStartRequest(aRequest As nsIRequest, aContext As nsISupports) Implements nsIRequestObserver.OnStartRequest
End Sub
Private Sub nsIRequestObserver_OnStopRequest(aRequest As nsIRequest, aContext As nsISupports, aStatusCode As Integer) Implements nsIRequestObserver.OnStopRequest
End Sub
End Class
The D:/truck.png and D:/truck2.png are same.
Why doesn't the picture appear in browser?

SerialPort.DataReceived event not firing

I've defined a SerialPort object as the following:
Public WithEvents SerialComm As New System.IO.Ports.SerialPort
SerialComm is setup and opened in the object constructor and closed when the object is disposed. My handler signature is as follows:
Private Sub OnComm(sender as Object, e as SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
I'm trying to get a DataReceived event to fire from HyperTerminal. After sending some data, I can set a breakpoint and check the value of SerialComm.BytesToRead and see that it has updated to the proper number of bytes.
I have confirmed that the SerialPort is open and is receiving data, but I can't get the event to fire.
I've also tried manually wiring up the event (after removing the WithEvents definition) using AddHandler, but I was still unable to get the event to trigger.
What am I missing?
Update:
This is the class that I'm having trouble with:
Imports System.IO.Ports
Public Class CopyCat
Implements IDisposable
Private RxString As String
Private LastReceiveTime As DateTime
Public WithEvents SerialComm As New SerialPort
Public Property Timeout As TimeSpan
Public Sub New(commPort As String, timeout As TimeSpan)
Me.Timeout = timeout
Enable(commPort)
End Sub
Public Sub New(commPort As String)
Me.New(commPort, TimeSpan.FromMilliseconds(1000))
End Sub
Public Sub Enable()
CommUtilities.SetupComm(SerialComm, commPort, 115200, 8, Parity.Odd, StopBits.One, Handshake.None, System.Text.Encoding.Default)
End Sub
Public Sub Disable()
SerialComm.Close()
End Sub
Private Sub OnComm(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
If(DateTime.Now - LastReceivedTime > Timeout) Then RxString = ""
Do While(SerialComm.BytesToRead > 0)
Dim readChar As String
Dim termChar As Char = Chr(RxString.ToByteList().XorAll())
readChar = SerialComm.ReadChar
RxString &= readChar
if (readChar = termChar) Then
SerialComm.Write((From item In GetResponse(RxString).Build()
Select item.Data).ToRawString)
RxString = ""
End If
Loop
End Sub
Public Function GetResponse(commandString As String) As MessageResponse
Dim response As MessageResponse = MessageResponse.GetMessageResponseFromByteList(commandString.ToByteList())
if (response.GetType = GetType(GetStatusResponse)) Then
response.DataBytes(8).Data = Math.Floor(Rnd() * 255)
response.DataBytes(9).Data = Math.Floor(Rnd() * 255)
End If
Return response
End Function
Private disposedValue as Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
SerialComm.Dispose()
End If
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class

Can't sort BindingSource from the first time on SelectedIndexChange

I have a sub which on SelectedIndexChange - of Customer returns the TransactionBindingSource.
What I want is to show on the databound controls the latest transaction of each selected customer instead of the first one. The weird thing is that when the tab loads (on the 'enter' event I call the selectedIndexChange method and the latest record is selected. However, when I manually select another customer, the first record of each transaction is displayed! This is what I have
Private Sub cboCustomerName_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboCustomerName.SelectedIndexChanged
resetstats()
'Try
Dim iTotalbuyin, iCountBuyins, iSumBuyins, iSumCashouts, iBiggestWin, iBiggestLoss As Integer
Dim oTotalbuyin, oCountBuyIns, oSumCashouts, oBiggestWin, oBiggestLoss As Object
' If Me.cboCustomerName.SelectedIndex <> -1 Then
Dim drv As DataRowView = CType(Me.cboCustomerName.SelectedItem, DataRowView)
Dim SelCustId As Integer = drv.Item("CustomerID")
Me.TransactionTableAdapter.Fill(Me.DbPBDataSet.Transaction, SelCustId)
Me.TransactionBindingSource.Sort = "TransactionID"
Me.TransactionBindingSource.MoveLast()
Any ideas?
You can make your own SortableBindingList class, like so:
Imports System.ComponentModel
Imports System.Reflection
Public Class SortableBindingList(Of T)
Inherits BindingList(Of T)
Private Property IsSorted As Boolean
Private Property SortDirection As ListSortDirection
Private Property SortProperty As PropertyDescriptor
Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
Get
Return True
End Get
End Property
Protected Overrides ReadOnly Property SortDirectionCore() As ListSortDirection
Get
Return _SortDirection
End Get
End Property
Protected Overloads Overrides ReadOnly Property SortPropertyCore() As PropertyDescriptor
Get
Return _SortProperty
End Get
End Property
Protected Overloads Overrides Sub ApplySortCore(ByVal PDsc As PropertyDescriptor, ByVal Direction As ListSortDirection)
Dim items As List(Of T) = TryCast(Me.Items, List(Of T))
If items Is Nothing Then
IsSorted = False
Else
Dim PCom As New PCompare(Of T)(PDsc.Name, Direction)
items.Sort(PCom)
IsSorted = True
SortDirection = Direction
SortProperty = PDsc
End If
OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
End Sub
Protected Overloads Overrides ReadOnly Property IsSortedCore() As Boolean
Get
Return _IsSorted
End Get
End Property
Protected Overrides Sub RemoveSortCore()
_IsSorted = False
End Sub
#Region " Constructors "
Sub New(ByVal list As ICollection(Of T))
MyBase.New(CType(list, Global.System.Collections.Generic.IList(Of T)))
End Sub
Sub New()
MyBase.New()
End Sub
#End Region
#Region " Property comparer "
Private Class PCompare(Of T)
Implements IComparer(Of T)
Private Property PropInfo As PropertyInfo
Private Property SortDir As ListSortDirection
Friend Sub New(ByVal SortProperty As String, ByVal SortDirection As ListSortDirection)
SortProperty = CheckPropertyName(SortProperty)
PropInfo = GetType(T).GetProperty(SortProperty)
SortDir = SortDirection
End Sub
''' <summary>
''' Used to change the name of the sorted property for certain classes.
''' </summary>
''' <param name="SortProperty"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function CheckPropertyName(ByVal SortProperty As String) As String
If SortProperty = "BinNumber" AndAlso GetType(T).Name = "BinReportDisplay" Then
Return "BinNumberSort"
End If
Return SortProperty
End Function
Friend Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
Return If(SortDir = ListSortDirection.Ascending, Comparer.[Default].Compare(PropInfo.GetValue(x, Nothing),
PropInfo.GetValue(y, Nothing)), Comparer.[Default].Compare(PropInfo.GetValue(y, Nothing),
PropInfo.GetValue(x, Nothing)))
End Function
End Class
#End Region
End Class
Then sort the list according to how you want it sorted.

Inotify change to another class or object

I am in a small fix, I have a class as below.
Public Class Bill
Public prime As BillPrime
Public items As System.Collections.ObjectModel.ObservableCollection(Of ItemDetails)
Public status As New BillStatus
Public Sub New()
prime = New BillPrime
items = New System.Collections.ObjectModel.ObservableCollection(Of ItemDetails)
status = New BillStatus
End Sub
End Class
How can I update some x value in prime when there is a change in any of the ItemDetails object in items.
Could you please help on how can I come to a solution?
Try using a BindingList(of T) instead, then you can listen for a change event:
Imports System.ComponentModel
Public Class Bill
Public prime As BillPrime
Public WithEvents items As BindingList(Of ItemDetails)
Public status As New BillStatus
Public Sub New()
prime = New BillPrime
items = New BindingList(Of ItemDetails)
status = New BillStatus
End Sub
Public Sub items_ListChanged(ByVal sender As Object, ByVal e As ListChangedEventArgs) Handles items.ListChanged
prime.X = "something"
End Sub
End Class
This would require your classes to implement INotifyPropertyChanged:
Public Class ItemDetails
Implements INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Private _DetailOne As String
Property DetailOne() As String
Get
Return _DetailOne
End Get
Set(ByVal value As String)
_DetailOne = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("DetailOne"))
End Set
End Property
End Class
The ItemDetails class will need to raise an event whenever any of its properties change. I would suggest implementing the INotifyPropertyChanged interface on the ItemDetails class, but you could implement your own event, instead. You will then need to add an event handler to each ItemDetails.PropertyChanged event as it is added to the list and remove the handler from each item as it is removed from the list. For instance:
Public Class Bill
Public prime As BillPrime
Public items As System.Collections.ObjectModel.ObservableCollection(Of ItemDetails)
Public status As New BillStatus
Public Sub New()
prime = New BillPrime
items = New System.Collections.ObjectModel.ObservableCollection(Of ItemDetails)
AddHandler items.CollectionChanged, AddressOf items_CollectionChanged
status = New BillStatus
End Sub
Private Sub items_CollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
For Each i as ItemDetails in e.NewItems
AddHandler i.PropertyChanged, AddressOf item_PropertyChanged
Next
For Each i as ItemDetails in e.OldItems
RemoveHandler i.PropertyChanged, AddressOf item_PropertyChanged
Next
End Sub
Private Sub item_PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
'Do work
End Sub
End Class