等待用户从后台选择
Wait for user to choose from the backend
我正在编写软件的后端部分,有时我需要我的用户选择一些东西,这可能是一个复杂的过程,用户甚至可以随时取消选择。
从后端我想做类似的事情:
private async void StartAction()
{
//some code
var SelectedItem = await UI.RequestUserToChooseItem();
// some final code using the selected item
}
这里我不知道如何处理取消,但我可以发送 null 并假设如果 SelectedItem
为 null 它已被取消。
但是 UI 部分呢?当用户选择事物时,如何处理 return 调用?
我需要在这里执行一些步骤:(这是伪代码,我什至不知道从哪里开始)
public List<Item> RequestUserToChooseItem()
{
PrepareItemsInList();
ShowSelectionPanel();
List<Items> SelectedItemsFromPanel = WaitForUserToChose(); //???????
return SelectedItemsFromPanel;
}
然后我们有取消按钮:
private void CancelButtonClicked(object sender, EventArgs e)
{
CancelWaitedSelectionProcessAndReturnNull(); //????
}
您可以使用 TaskCompletionSource 来表示选择。像
private TaskCompletionSource<MyOptions> tcs;
public Task<MyOptions> ShowPanelAndWaitForSelection(){
// show panel and do other initialization
tcs = new TaskCompletionSource<MyOptions>();
return tcs.Task;
}
public void OnOptionSelection(MyOptions value) => tcs.SetResult(value);
public void OnCanceled() => tcs.SetCanceled();
当任务被取消时,任何等待者都会得到一个 OperationCanceledException
,因此您的代码通常类似于:
try{
...
var selectedOption = await ShowPanelAndWaitForSelection();
...
}
catch(OperationCanceledException){
// Handle cancellation
}
catch(Exception e){
// Handle actual errors
}
这假设您的 UI 是 non-modal,就像以相同的形式显示和隐藏面板一样。如果您对每个步骤都使用模态对话框,则不需要任何异步代码。
这种风格本质上是利用编译器生成状态机,而不是手工编写这样的状态机。我认为这可能是一种处理特定情况的有用样式,因为您可以使用 if/while 等常规结构来制作决策树。但这可能并不总是绝对积极的,并且可能会绊倒不这样做的开发人员敬请期待
这是一个异步方法,它异步等待第一次点击一个或多个按钮,并且returns被点击的按钮:
public static Task<Button> OnClickAsync(params Button[] buttons)
{
var tcs = new TaskCompletionSource<Button>();
foreach (var button in buttons) button.Click += OnClick;
return tcs.Task;
void OnClick(object sender, RoutedEventArgs e)
{
foreach (var button in buttons) button.Click -= OnClick;
tcs.SetResult((Button)sender);
}
}
可以这样使用:
public async Task<List<Item>> RequestUserToChooseItemAsync()
{
PrepareItemsInList();
ShowSelectionPanel();
var selectedButton = await OnClickAsync(btnOK, btnCancel);
if (selectedButton == btnCancel) return null;
return SelectedItemsFromPanel;
}
此方法应该在 UI 线程上专门调用,而不是在后台线程上调用,因为它与 UI 元素交互。
我正在编写软件的后端部分,有时我需要我的用户选择一些东西,这可能是一个复杂的过程,用户甚至可以随时取消选择。
从后端我想做类似的事情:
private async void StartAction()
{
//some code
var SelectedItem = await UI.RequestUserToChooseItem();
// some final code using the selected item
}
这里我不知道如何处理取消,但我可以发送 null 并假设如果 SelectedItem
为 null 它已被取消。
但是 UI 部分呢?当用户选择事物时,如何处理 return 调用?
我需要在这里执行一些步骤:(这是伪代码,我什至不知道从哪里开始)
public List<Item> RequestUserToChooseItem()
{
PrepareItemsInList();
ShowSelectionPanel();
List<Items> SelectedItemsFromPanel = WaitForUserToChose(); //???????
return SelectedItemsFromPanel;
}
然后我们有取消按钮:
private void CancelButtonClicked(object sender, EventArgs e)
{
CancelWaitedSelectionProcessAndReturnNull(); //????
}
您可以使用 TaskCompletionSource 来表示选择。像
private TaskCompletionSource<MyOptions> tcs;
public Task<MyOptions> ShowPanelAndWaitForSelection(){
// show panel and do other initialization
tcs = new TaskCompletionSource<MyOptions>();
return tcs.Task;
}
public void OnOptionSelection(MyOptions value) => tcs.SetResult(value);
public void OnCanceled() => tcs.SetCanceled();
当任务被取消时,任何等待者都会得到一个 OperationCanceledException
,因此您的代码通常类似于:
try{
...
var selectedOption = await ShowPanelAndWaitForSelection();
...
}
catch(OperationCanceledException){
// Handle cancellation
}
catch(Exception e){
// Handle actual errors
}
这假设您的 UI 是 non-modal,就像以相同的形式显示和隐藏面板一样。如果您对每个步骤都使用模态对话框,则不需要任何异步代码。
这种风格本质上是利用编译器生成状态机,而不是手工编写这样的状态机。我认为这可能是一种处理特定情况的有用样式,因为您可以使用 if/while 等常规结构来制作决策树。但这可能并不总是绝对积极的,并且可能会绊倒不这样做的开发人员敬请期待
这是一个异步方法,它异步等待第一次点击一个或多个按钮,并且returns被点击的按钮:
public static Task<Button> OnClickAsync(params Button[] buttons)
{
var tcs = new TaskCompletionSource<Button>();
foreach (var button in buttons) button.Click += OnClick;
return tcs.Task;
void OnClick(object sender, RoutedEventArgs e)
{
foreach (var button in buttons) button.Click -= OnClick;
tcs.SetResult((Button)sender);
}
}
可以这样使用:
public async Task<List<Item>> RequestUserToChooseItemAsync()
{
PrepareItemsInList();
ShowSelectionPanel();
var selectedButton = await OnClickAsync(btnOK, btnCancel);
if (selectedButton == btnCancel) return null;
return SelectedItemsFromPanel;
}
此方法应该在 UI 线程上专门调用,而不是在后台线程上调用,因为它与 UI 元素交互。