У меня есть сетка данных, связанная с наблюдаемой коллекцией. Каждый элемент в сетке может иметь несколько подробных линий, которые хранятся в наблюдаемом свойстве коллекции внутри основного объекта.
Сведения о строке извлекаются из связанного сервера с медленным подключением, поэтому я хотел бы добавить фонового работника для обновления OC сведений о строке, но я получаю сообщение об ошибке, сообщающее, что элемент управления не может быть обновлен вне нити, которая сделала это.
Какой лучший способ сделать это. 2-секундное отставание немного больше.
датагрид xaml:
<DataGrid AutoGenerateColumns="False" Name="dgROList" ItemsSource="{Binding ElementName=MainWindow, Path=cROInfo}" CanUserDeleteRows="True" CanUserReorderColumns="False" GridLinesVisibility="Horizontal" Margin="0,112,0,0" Grid.ColumnSpan="2" AlternatingRowBackground="#FFFFE776">
<DataGrid.Columns>
<DataGridTextColumn Header="RO Number" Width="Auto" Binding="{Binding RONum}" />
<DataGridTemplateColumn x:Name="roDetails" Header="RO Details" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl Name="LineDetails" ItemsSource="{Binding LineInfo}" Width="Auto">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ItemsPresenter />
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Line}" />
<Label Content="{Binding Status}" />
<Label Content="{Binding PaidAmount}" />
<Label Content="{Binding SDate}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--<DataGridTextColumn Header="RO Details" Width="*" Binding="{Binding RODetails}" />-->
</DataGrid.Columns>
</DataGrid>
OC класс:
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Public Class ocROInformation
Implements INotifyPropertyChanged
Private _RONum As String
Private _LineInfo As ObservableCollection(Of ocROLineInformation)
Private _Changed As Boolean
Private _RONumChanged As Boolean
Private _RODetailsChanged As Boolean
Private WithEvents bgworker As BackgroundWorker
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Public Sub New(ronum As String)
_RONum = ronum
_LineInfo = New ObservableCollection(Of ocROLineInformation)
bgworker = New BackgroundWorker
bgworker.RunWorkerAsync()
' GetData() ' If I call this directly it works, just lags out while the query runs for a little bit.
End Sub
Protected Overridable Sub OnPropertyChanged(ByVal Propertyname As String)
If Not Propertyname.Contains("Changed") Then
Changed = True
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Propertyname))
End Sub
Sub GetData() Handles bgworker.DoWork
Dim DCodes As String = DealerCodes
Dim rSelect As New ADODB.Recordset
Dim sSql As String = "SELECT DISTINCT * FROM IGlobal WHERE RMAJBC = " & _RONum"
Dim line As Integer
Dim status As String = ""
Dim sdate As Date
Dim paidamount As Double
Dim tdate As String
With rSelect
.Open(sSql, MyCn, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockReadOnly)
If .EOF Then
status = "Never Received"
End If
Do While Not .EOF
line = .Fields!LineNum.Value
status = NZ(.Fields!Stat6.Value, "")
paidamount = NZ(.Fields!PaidAmount.Value, 0)
tdate = NZ(.Fields!SDate.Value, "")
If Not tdate = "" And Not tdate = "0" Then
sdate = Date.ParseExact(tdate, "yyyyMMdd", System.Globalization.DateTimeFormatInfo.InvariantInfo)
_LineInfo.Add(New ocROLineInformation(line, status, sdate, paidamount))
Else
_LineInfo.Add(New ocROLineInformation(line, status))
End If
.MoveNext()
Loop
.Close()
End With
OnPropertyChanged("RODetails")
End Sub
Public Property Changed() As Boolean
Get
Return _Changed
End Get
Set(ByVal value As Boolean)
If _Changed <> value Then
_Changed = value
OnPropertyChanged("Changed")
End If
End Set
End Property
Public Property RONum() As String
Get
Return _RONum
End Get
Set(value As String)
If _RONum <> value Then
_RONum = value
RONumChanged = True
OnPropertyChanged("RONum")
GetData()
End If
End Set
End Property
Public ReadOnly Property RODetails As String
Get
Dim output As String = ""
For Each l As ocROLineInformation In _LineInfo
output &= l.Print & " "
Next
Return output '"This is a test: " & _RONum
End Get
End Property
Public ReadOnly Property LineInfo As ObservableCollection(Of ocROLineInformation)
Get
Return _LineInfo
End Get
End Property
Public Property RODetailsChanged As Boolean
Get
Return _RODetailsChanged
End Get
Set(value As Boolean)
If _RODetailsChanged <> value Then
_RODetailsChanged = value
OnPropertyChanged("RODetailsChanged")
End If
End Set
End Property
Public Property RONumChanged() As Boolean
Get
Return _RONumChanged
End Get
Set(value As Boolean)
If _RONumChanged <> value Then
_RONumChanged = value
OnPropertyChanged("RONumChanged")
End If
End Set
End Property
End Class
Public Class ocROLineInformation
Implements INotifyPropertyChanged
Private _Line As Integer
Private _Status As String
Private _SDate As Date
Private _PaidAmount As Double
Private _Changed As Boolean
Private _LineChanged As Boolean
Private _StatusChanged As Boolean
Private _SDateChanged As Boolean
Private _PaidAmountChanged As Boolean
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Public Sub New(line As Integer, status As String, sdate As Date, paidamount As Double)
_Line = line
_Status = status
_SDate = sdate
_PaidAmount = paidamount
End Sub
Public Sub New(line As Integer, status As String)
_Line = line
_Status = status
End Sub
Public ReadOnly Property Print() As String
Get
Return "Line: " & _Line & ", Status: " & _Status & ", Amount: " & _PaidAmount & ", Date: " & _SDate.ToShortDateString
End Get
End Property
Protected Overridable Sub OnPropertyChanged(ByVal Propertyname As String)
If Not Propertyname.Contains("Changed") Then
Changed = True
End If
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Propertyname))
End Sub
Public Property Changed() As Boolean
Get
Return _Changed
End Get
Set(ByVal value As Boolean)
If _Changed <> value Then
_Changed = value
OnPropertyChanged("Changed")
End If
End Set
End Property
Public Property Line() As Integer
Get
Return _Line
End Get
Set(value As Integer)
If _Line <> value Then
_Line = value
LineChanged = True
OnPropertyChanged("Line")
End If
End Set
End Property
Public Property Status() As String
Get
Return _Status
End Get
Set(value As String)
If _Status <> value Then
_Status = value
StatusChanged = True
OnPropertyChanged("Status")
End If
End Set
End Property
Public Property SDate() As Date
Get
Return _SDate
End Get
Set(value As Date)
If _SDate <> value Then
_SDate = value
SDateChanged = True
OnPropertyChanged("SDate")
End If
End Set
End Property
Private Property PaidAmount() As Double
Get
Return _PaidAmount
End Get
Set(value As Double)
If _PaidAmount <> value Then
_PaidAmount = value
PaidAmountChanged = True
OnPropertyChanged("PaidAmount")
End If
End Set
End Property
Public Property LineChanged() As Boolean
Get
Return _LineChanged
End Get
Set(value As Boolean)
If _LineChanged <> value Then
_LineChanged = value
OnPropertyChanged("LineChanged")
End If
End Set
End Property
Public Property StatusChanged() As Boolean
Get
Return _StatusChanged
End Get
Set(value As Boolean)
If _StatusChanged <> value Then
_StatusChanged = value
OnPropertyChanged("StatusChanged")
End If
End Set
End Property
Public Property SDateChanged() As Boolean
Get
Return _SDateChanged
End Get
Set(value As Boolean)
If _SDateChanged <> value Then
_SDateChanged = value
OnPropertyChanged("SDateChanged")
End If
End Set
End Property
Public Property PaidAmountChanged() As Boolean
Get
Return _PaidAmountChanged
End Get
Set(value As Boolean)
If _PaidAmountChanged <> value Then
_PaidAmountChanged = value
OnPropertyChanged("PaidAmountChanged")
End If
End Set
End Property
End Class