我正在尝试使用包含SearchResult
的{{1}}的ObservableCollection填充ListView。我的(简化的)数据结构是:
ObservableCollection<Inline>
它包含一个public class SearchResult
{
public static ObservableCollection<Inline> FormatString(string s)
{
ObservableCollection<Inline> inlineList = new ObservableCollection<Inline>
{
new Run("a"),
new Run("b") { FontWeight = FontWeights.Bold },
new Run("c")
};
return inlineList;
}
public ObservableCollection<Inline> Formatted { get; set; }
public string Raw { get; set; }
}
,因为这些SearchResults将与支持富文本的自定义ObservableCollection<Inline>
一起显示:
BindableTextBlock
但是当填充ListView时
public class BindableTextBlock : TextBlock
{
public ObservableCollection<Inline> InlineList
{
get { return (ObservableCollection<Inline>)GetValue(InlineListProperty); }
set { SetValue(InlineListProperty, value); }
}
public static readonly DependencyProperty InlineListProperty = DependencyProperty.Register("InlineList", typeof(ObservableCollection<Inline>), typeof(BindableTextBlock), new UIPropertyMetadata(null, OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
BindableTextBlock textBlock = (BindableTextBlock)sender;
textBlock.Inlines.Clear();
textBlock.Inlines.AddRange((ObservableCollection<Inline>)e.NewValue);
}
}
使用以下BackgroundWorker
<ListView Name="allSearchResultsListView">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<local:BindableTextBlock InlineList="{Binding Formatted}" />
<TextBlock Text="{Binding Raw}" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
程序崩溃与
public partial class MainWindow : Window
{
private readonly BackgroundWorker worker = new BackgroundWorker();
ObservableCollection<SearchResult> searchResults = new ObservableCollection<SearchResult>();
public MainWindow()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (long i = 0; i < 1000; i++)
{
searchResults.Add(new SearchResult()
{
Formatted = SearchResult.FormatString("a*b*c"),
Raw = "abc"
});
}
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
allSearchResultsListView.ItemsSource = searchResults;
}
}
Exception thrown: 'System.Windows.Markup.XamlParseException' in PresentationFramework.dll
问题是在后台工作程序UI元素(Inner Exception: The calling thread cannot access this object because a different thread owns it
)中创建了不属于UI线程的元素。在工作人员完成后分配ItemsSource时,将引发异常。
相似的问题似乎被问了很多,但我找不到适合我的特殊情况的东西。
感谢您的帮助!
答案 0 :(得分:2)
要与UI元素进行交互,您必须在UI线程分派器中使用“ Invoke”或“ BeginInvoke”
Application.Current.Dispatcher.Invoke((Action)delegate
{
//CHANGE DATA BOUND TO THE UI HERE
});
我喜欢使用静态方法:
public static class Helpers
{
public static void RunInUIThread(Action method)
{
if (Application.Current == null)
{
return;
}
Application.Current.Dispatcher.BeginInvoke((Action)delegate
{
method();
});
}
}
您可以这样使用它:
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Helpers.RunInUIThread(()=>allSearchResultsListView.ItemsSource = searchResults);
}
顺便说一句,您应该使用后台线程进行长时间运行的操作,例如从Web服务获取数据。