我有一个绑定到可观察集合的数据网格。网格内的每个项目都可以有多个细节线,这些细节线存储在主对象内部的可观察集合属性中。
正在从连接速度较慢的链接服务器获取行详细信息,因此我想让后台工作人员更新行详细信息OC,但是我收到一条错误消息,指出控件无法更新在制作它的线程之外。
最好的方法是什么? 2秒的延迟有点多了。
datagrid 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
答案 0 :(得分:1)
您需要在UI线程上更新集合。为此,请确保通过Result
上的DoWorkEventArgs
属性传回数据。
在完成的事件中,您可以通过RunWorkerCompletedEventArgs.Result
属性运行数据,并相应地设置ObservableCollection
,所有这些都在UI线程上。
如果您想避开BackgroundWorker
,可以使用Dispatcher
。
ThreadStart start = delegate()
{
// make your calls to the db
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action<object>(UpdateCollection),
new object[] { myData });
};
new Thread(start).Start();
private void UpdateCollection(object data)
{
//iterate your collection and add the data as needed
}
无论你走哪条路,根本原因是试图从不同的线程访问在UI线程上创建的对象。