這張圖片是我關于 STA 執行緒的錯誤。
- 專案正在等待傳入資料。其實我不想只是等待申請。我正在嘗試使用調度程式或任務,但我遇到了這個錯誤。
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
ToggleStart();
var stackPanel = await Task.Run(TaskCheckBoxZones).ConfigureAwait(false);
ZonesBorder.Child = stackPanel;
//await Dispatcher.BeginInvoke((Action)async delegate
//{
// var findCheckBoxes = new FindCheckBoxes
// {
// CheckBoxItemTab = CheckBoxPanel,
// CheckBoxItemTab2 = CheckBoxPanel2,
// Token = token,
// };
// await findCheckBoxes.LoadPaymentsMethods();
//});
}
async Task<StackPanel> TaskCheckBoxZones()
{
var stackPanel = await new CreateCheckBoxZones()
{
Token = token
}.LoadZonesData();
return stackPanel;
}
Settings.xaml.cs 中的上述代碼塊
public class CreateCheckBoxZones
{
private List<OrderZones> OrderZonesList;
public string Token = "";
public CreateCheckBoxZones()
{
OrderZonesList = new List<OrderZones>();
_innerStack = new StackPanel();
}
//public Border Border;
private StackPanel _innerStack;
public StackPanel InnerStack
{
get { return _innerStack; }
set { _innerStack = value; }
}
public async Task<StackPanel> LoadZonesData()
{
OrderZonesList = await MapOrderZones();
foreach (var zone in OrderZonesList)
{
CheckBox cb = new CheckBox();
cb.Tag = zone.Id;
cb.Content = zone.Name;
cb.IsChecked = zone.Status == 100;
cb.Click = ZonesCheckBox_Click;
_innerStack.Children.Add(cb);
}
return _innerStack;
}
private async Task<List<OrderZones>> MapOrderZones()
{
var zoneModels = await TakeZones();
if (zoneModels[0]._id == null)
throw new Exception("Zones is can not null.");
foreach (var zone in zoneModels)
{
OrderZonesList.Add(new OrderZones(
zone._id,
zone.placement,
zone.name.tr,
zone.minBasketSize,
zone.status,
zone.restaurant));
}
return OrderZonesList;
}
public async Task<List<ZoneModel>> TakeZones()
{
try
{
string url = Constants.GET_ZONES;
var response = await new WebClient<List<ZoneModel>>()
{
Endpoint = url,
Token = Token,
Method = Method.GET
}.SendToAPIAsync();
if (response.ErrorException != null)
{
MessageBox.Show("B?lgeleri al?rken, bir hata ald?n.", "B?lgeler", MessageBoxButton.OK, MessageBoxImage.Error);
}
return response.Data;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return null;
}
上面的代碼塊是關于我的 LoadCheckbox 類,這個類使用我獲取資料的端點獲取一些 API 資訊,但是。在 UI 上選擇“定義”復選框時,我的應用程式凍結。我正在尋找一些解決方案。
uj5u.com熱心網友回復:
您應該使用 a ListBox(而不是 a StackPanel)和 aDataTemplate來生成專案(包括CheckBox)。
async永遠不要將方法包裝到Task.Run! 既然TaskCheckBoxZones是一種async方法,那Task.Run(TaskCheckBoxZones)就是禁忌。TaskCheckBoxZones或異步方法通常應以“異步”后綴命名,例如TaskCheckBoxZonesAsync. 這將幫助您識別異步方法以正確處理它們。- 你用
ConfigureAwait(false)錯了。旨在通過允許繼續在執行緒池執行緒上執行ConfigureAwait(false)來避免背景關系切換回捕獲的內容。SynchronizationContext例如,當 aTask捕獲SynchronizationContext主執行緒的當前執行緒時,使用它配置它ConfigureAwait(false)可能會強制繼續,即 , 之后的代碼在await非 UI 執行緒上執行。
在 UI 背景關系中使用ConfigureAwait(false)很可能會拋出InvalidOperationException指示非法的跨執行緒操作:
private void OnLoaded(object sender, EventArgs e)
{
/** UI thread context **/
// Task captures the current SynchronizationContext which is the UI thread.
var stackPanel = await Task.Run(TaskCheckBoxZones) // Never wrap an async method into a Task.Run
.ConfigureAwait(false); // ConfigureAwait(false) will force continuation on a non UI thread.
/** Worker thread context (non UI) **/
ZonesBorder.Child = stackPanel; // Will throw InvalidOperationException (cross-thread)
要解決此問題,您通常不應ConfigureAwait(false)在 UI 背景關系中使用。它適用于非 UI 庫代碼。async在 UI 級別或應用程式級別背景關系中,您很可能希望在操作完成后回傳 UI 執行緒:
private void OnLoaded(object sender, EventArgs e)
{
/** UI thread context **/
// Task captures the current SynchronizationContext which is the UI thread.
// Since ConfigureAwait(true) is the default behavior, the Task will return to the UI thread.
var stackPanel = await TaskCheckBoxZonesAsync();
/** UI thread context **/
ZonesBorder.Child = stackPanel; // Access allowed
- 不要使用
Dispatcher.BeginInvoke. 它是一種古老的方法,屬于 pre async/await API 時代的一部分。從 .NET Framework 4.5 開始,我們使用Dispatcher.InvokeAsync. - 不要將在 UI 執行緒上執行的代碼排入
Dispatcher. 此外,在這種情況下等待Dispatcher絕對是多余的。規則 1) 也適用于:避免將方法Dispatcher包裝到呼叫中:asyncDispatcher
你的壞版本
await Dispatcher.BeginInvoke((Action)async delegate
{
var findCheckBoxes = new FindCheckBoxes
{
CheckBoxItemTab = CheckBoxPanel,
CheckBoxItemTab2 = CheckBoxPanel2,
Token = token,
};
await findCheckBoxes.LoadPaymentsMethods();
});
正確的版本
var findCheckBoxes = new FindCheckBoxes
{
CheckBoxItemTab = CheckBoxPanel,
CheckBoxItemTab2 = CheckBoxPanel2,
Token = token,
};
await findCheckBoxes.LoadPaymentsMethodsAsync();
- Don't create a background thread only to create a control on the
Dispatcher. This is absolutely pointless and expensive. If instantiation of your control is expensive consider to use anasyncinitialization routine. Generally calling a constructor on a background thread is a serious code smell and an indicator of a poorly written class. A constructor must return immediately. A constructor should never be long-running:
Your bad version
private asnyc void OnButton_Click(object sender, EventArgs e)
{
await Task.Run(() => Dispatcher.InvokeAsync(new MyDialogWindow().ShowDialog));
}
The correct version
private asnyc void OnButton_Click(object sender, EventArgs e)
{
var dialog = new MyDialogWindow();
await dialog.InitializeAsync(); // Perform longrunning and CPU intensive or IO initialization in a non blocking manner
dialog.ShowDialog();
}
- There is no reason to let a
privatemethod return a member (e.g., a property). Just make it returnvoid. - Never catch the base class
Exceptionand never show exception messages to the user. If you can recover from a particular exception, then only catch this one. Let the application crash on any other exception.
Solution
MainWindow.xaml.cs
partial class MainWIndow : Window
{
// Use Clear, Add and Remove to modify this collection during runtime.
// If you need to replace the complete collection (not recommended), then make this property into a dependency property.
public ObservableCollection<OrderZone> OrderZones { get; }
public MainWindow()
{
InitializeComponent();
this.ZoneModels = new ObservableCollection<OrderZone>();
this.Loaded = onl oaded;
}
private async void OnLoaded(object sender, EventArgs e)
{
var zoneCreator = new OrderZoneCreator();
IAsyncEnumerable<OrderZone> orderZones = zoneCreator.EnumerateOrderZonesAsync();
await foreach (OrderZone orderZone in orderZones)
{
this.OrderZones.Add(orderZone);
}
}
}
ZoneModelCreator.cs
public class OrderZoneCreator
{
public async IAsyncEnumerable<OrderZone> EnumerateOrderZonesAsync()
{
List<ZoneModel> zoneModels = await GetZonesAsync();
foreach (var zone in zoneModels)
{
var newOrderZone = new OrderZone(
zone._id,
zone.placement,
zone.name.tr,
zone.minBasketSize,
zone.status,
zone.restaurant);
yield return newOrderZone;
}
}
private async Task<List<ZoneModel>> GetZonesAsync()
{
string url = Constants.GET_ZONES;
var webClient = new WebClient<List<ZoneModel>>()
{
Endpoint = url,
Token = Token,
Method = Method.GET
};
var response = await webClient.SendToAPIAsync();
if (response.ErrorException != null)
{
// This is an internal operation and shouldn't generate user messages
// as the user can't do anything to make this operation succeed.
// Throw an exception if this error is not acceptable
// or do nothing and return an empty collection.
return new List<ZoneModel>();
}
return response.Data;
}
}
StatusToBooleanConverter.cs
class StatusToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> value is OrderZone orderZone
? orderZone.Status == 100
: Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
MainWindow.xaml
<Window>
<Window.Resources>
<local:StatusToBooleanConverter x:Key="StatusToBooleanConverter" />
</Window.Resources>
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=OrderZones}"
BorderBrush="Black"
BorderThickness=2>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:OrderZone}">
<CheckBox Content="{Binding Name, Mode OneTime}"
Tag="{Binding Id, Mode OneTime}"
Click="ZonesCheckBox_Click"
IsChecked="{Binding Status, Converter={StaticResource StatusToBooleanConverter}, Mode OneTime}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/457406.html
