我之前发过一个类似的问题,但现在我正在根据我决定采用的具体方法来定制这个问题。
简单地说,我想要做的是在用户点击一个页面后显示加载消息,当下一页完全加载时消失(将27000个公司加载到DataGrid中),然后显示下一页。订单看起来像这样;
我建议使用async
和wait
。然而,这冻结了我的UI并且无法工作(Additional information: The calling thread cannot access this object because a different thread owns it.
)。然后我开始考虑使用多个线程,这有望解决我的问题。这是我到目前为止所尝试的;
用户已点击按钮进入下一页
public CompanyManagement()
{
InitializeComponent();
Thread thread = Thread.CurrentThread;
this.DataContext = new
{
ThreadId = thread.ManagedThreadId
};
}
调用Page的Loaded事件;
private void PageLoaded(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
var wait = new PleaseWait("My title", "My Message", () => FillDataGrid());
wait.ShowDialog();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
FillDataGrid()是一直占用的方法(通过OleDB检索公司),看起来像这样;
private void FillDataGrid()
{
var _cDS = new CompanyDataService();
var Companies = new ObservableCollection<CompanyModel>();
Companies = _cDS.HandleCompanySelect();
CompanyICollectionView = CollectionViewSource.GetDefaultView(Companies);
//CompanyICollectionView.SortDescriptions.Add(new SortDescription("CompanyName", ListSortDirection.Ascending));
DataContext = this;
cancelButton.Visibility = Visibility.Hidden;
if (compNameRad.IsChecked == false &&
compTownRad.IsChecked == false &&
compPcodeRad.IsChecked == false)
{
searchBox.IsEnabled = false;
}
dataGrid.SelectedIndex = 0;
SetDefaultFilter();
}
这几乎可以工作,下一页被加载,显示“Please Wait ....”然后我得到错误:调用线程无法访问此对象,因为另一个线程拥有它。我是否错误地使用了线程功能?
编辑:我也应该展示PleaseWait
!
public partial class PleaseWait : Window
{
readonly Action _action;
public PleaseWait(string title, string message, Action action)
{
_action = action;
InitializeComponent();
this.Title = title;
this.label.Content = message;
}
private async void loaded(object sender, RoutedEventArgs e)
{
await Task.Run(() => _action());
this.Close();
}
}
编辑:对于StepUp;
private void PageLoaded(object sender, RoutedEventArgs e)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
var wait = new PleaseWait("My title", "My Message", () => FillDataGrid());
wait.ShowDialog();
Dispatcher.Run();
}));
}
答案 0 :(得分:0)
通常,WPF应用程序以两个线程开头:一个用于处理 渲染和另一个用于管理UI。渲染线程 在UI线程接收时有效地隐藏在后台 输入,处理事件,绘制屏幕并运行应用程序代码。 尽管在某些情况下,大多数应用程序使用单个UI线程 最好使用几个。
UI线程将名为Dispatcher的对象内的工作项排队。 Dispatcher优先选择工作项并运行每个工作项 一到完成。每个UI线程必须至少有一个Dispatcher, 并且每个Dispatcher都可以在一个线程中执行工作项。
您正在从非UI线程更新UI,因此您遇到了异常。
private void FillDataGrid()
{
var _cDS = new CompanyDataService();
var Companies = new ObservableCollection<CompanyModel>();
Companies = _cDS.HandleCompanySelect();
CompanyICollectionView = CollectionViewSource.GetDefaultView(Companies);
//CompanyICollectionView.SortDescriptions.Add(new SortDescription("CompanyName", ListSortDirection.Ascending));
DataContext = this;
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
cancelButton.Visibility = Visibility.Hidden;
if (compNameRad.IsChecked == false && compTownRad.IsChecked == false &&
compPcodeRad.IsChecked == false)
{
searchBox.IsEnabled = false;
}
dataGrid.SelectedIndex = 0;
}));
SetDefaultFilter();
}
<强>更新强> 此代码不符合条件:
private void PageLoaded(object sender, RoutedEventArgs e)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
var wait = new PleaseWait("My title", "My Message", () => FillDataGrid());
wait.ShowDialog();
Dispatcher.Run();
}));
}
在PageLoaded
内创建新主题时。这意味着在UI线程中创建新线程并从非UI线程更新UI。也就是说,您正在更新没有Dispatcher
的UI。您应该在新创建的Dispatcher
内使用thread
来更新UI
。