后台等待用户选择

发布于 2025-01-11 11:13:19 字数 832 浏览 0 评论 0原文

我正在编写软件的后端部分,有时我需要用户选择一些东西,这可能是一个复杂的过程,用户甚至可以随时取消选择。

从后端我想做一些类似的事情:

private async void StartAction()
{
    //some code
    var SelectedItem = await UI.RequestUserToChooseItem();
    // some final code using the selected item
}

这里我不知道如何处理取消,但我可以发送 null 并假设如果 SelectedItem 为 null 它被取消。

但是它的 UI 部分呢?当用户选择该事物时,如何处理以返回呼叫?

我需要在这里执行一些步骤:(这是伪代码,我什至不知道从哪里开始)

public List<Item> RequestUserToChooseItem()
{
    PrepareItemsInList();
    ShowSelectionPanel();
    List<Items> SelectedItemsFromPanel = WaitForUserToChose(); //???????
    return SelectedItemsFromPanel;

}

然后我们有取消按钮:

private void CancelButtonClicked(object sender, EventArgs e)
{
    CancelWaitedSelectionProcessAndReturnNull(); //????
}

I'm coding the backend portion of a software and at some point I need my user to choose some things, it can be a convoluted process, the user can even cancel the selection at any point.

From the back end I'd like to do something like:

private async void StartAction()
{
    //some code
    var SelectedItem = await UI.RequestUserToChooseItem();
    // some final code using the selected item
}

Here I don't know how to handle cancellation, but I can send null and assume that if the SelectedItem is null it was canceled.

But what about the UI portion of it? How do I handle it to return the call when the thing is selected by the user?

I need to perform some steps here: (this is pseudocode, I don't even know where to start)

public List<Item> RequestUserToChooseItem()
{
    PrepareItemsInList();
    ShowSelectionPanel();
    List<Items> SelectedItemsFromPanel = WaitForUserToChose(); //???????
    return SelectedItemsFromPanel;

}

And then we have the cancel button:

private void CancelButtonClicked(object sender, EventArgs e)
{
    CancelWaitedSelectionProcessAndReturnNull(); //????
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

琴流音 2025-01-18 11:13:19

您可以使用 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 是非模式的,例如以相同的形式显示和隐藏面板。如果您为每个步骤使用模式对话框,则不需要任何异步代码。

这种风格本质上是使用编译器生成状态机,而不是手动编写这样的状态机。我认为这可能是处理特定情况的有用风格,因为您可以使用 if/while 等常规结构来制作决策树。但它可能并不总是积极的,并且可能会让不期望的开发人员绊倒。

You can use a TaskCompletionSource to signal the choices. Something like

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();

When if the task is canceled, any awaiter will get a OperationCanceledException, so your code would normally look something like:

try{
    ...
    var selectedOption = await ShowPanelAndWaitForSelection();
    ...
}
catch(OperationCanceledException){
    // Handle cancellation
}
catch(Exception e){
   // Handle actual errors
}

This assumes your UI is non-modal, like showing and hiding panels in the same form. If you use modal dialogs for each step you do not need any async code.

This style essentially uses the compiler to generate a state machine, instead of writing such a state machine by hand. I think this can be a useful style to handle specific cases, since you can make a decision tree using regular constructs like if/while etc. But it may not always be a net positive, and it may trip up developers that do not expect it.

怀中猫帐中妖 2025-01-18 11:13:19

下面是一个异步方法,它异步等待第一次单击一个或多个按钮,并返回单击的按钮:

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 元素。

Here is an asynchronous method that waits asynchronously for the first click on one or more buttons, and returns the clicked button:

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);
    }
}

It could be used like this:

public async Task<List<Item>> RequestUserToChooseItemAsync()
{
    PrepareItemsInList();
    ShowSelectionPanel();
    var selectedButton = await OnClickAsync(btnOK, btnCancel);
    if (selectedButton == btnCancel) return null;
    return SelectedItemsFromPanel;
}

This method should be called exclusively on the UI thread, not on background threads, because it interacts with UI elements.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文