Search code examples
wpfvb.netxamlcontrolsshared

Make WPF-control shared


I'm trying to access Label from another class's method running in background thread with the help of MainWindow Class's Public Shared Sub like this:

    Private Delegate Sub ProgressReportInvoker(ByVal progressStr As String)

    Public Shared Sub ProgressReport(ByVal progressStr As String)
        If MainWindow.Label.Dispatcher.CheckAccess() Then
            MainWindow.Label.Content = progressStr
        Else
            MainWindow.Label.Dispatcher.Invoke(
                            New ProgressReportInvoker(AddressOf ProgressReport),
                            progressStr)
        End If
    End Sub

Call from another class is below:

MainWindow.ProgressReport("Sample text") 

But I have this error on "MainWindow.Label":

Reference to a non-shared member requires an object reference.

I noticed that if I declare Label in MainWindow.g.i.vb as Public Shared than error is gone:

#ExternalSource ("..\..\MainWindow.xaml", 11)
    <System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")>
    Public Shared WithEvents Label As System.Windows.Controls.Label

#End ExternalSource

But this file is generated automatically from the *.XAML file so it takes previous look when I compile the code.

Is there any way to make control shared in *.XAML file or may be there are any alternatives of making my task possible?


Solution

  • You should access the instance of the MainWindow and not the type itself:

    Public Shared Sub ProgressReport(ByVal progressStr As String)
        Dim mainWindow = Application.Current.Windows.OfType(Of MainWindow).FirstOrDefault()
        If mainWindow.Label.Dispatcher.CheckAccess() Then
            mainWindow.Label.Content = progressStr
        Else
            mainWindow.Label.Dispatcher.Invoke(
                                New ProgressReportInvoker(AddressOf ProgressReport),
                                progressStr)
        End If
    End Sub
    

    I tried this before but problem is in multitasking. I can't access the form from another thread without some special moves which I don't know about

    You can only access a UI control in the thread on which it was originally created:

    Application.Current.Dispatcher.BeginInvoke(New Action(Sub()
                                                              Dim mainWindow = Application.Current.Windows.OfType(Of MainWindow).FirstOrDefault()
                                                              mainWindow.Label.Content = progressStr
                                                          End Sub))