Return value from usercontrol after user action

2019-07-07 06:01发布

问题:

Essentially I need the same thing that Form.ShowDialog() offers, but with a UserControl.

Inside a winform, I load a UserControl, which should allow a user to select an item from a list, and return it back to the caller.

For example:

var item = myUserControl.SelectItem();

Obviously, returning from a control's method is very simple. But how can I make it wait until user performs the required action with the control?

I can subscribe to an event of the control, but this path is not ideal.

Put simply, I want a UserControl's method to return after user clicks a specific button on it.

回答1:

Simply put, a UserControl is really just a custom control and just like you drop a TextBox or a ListBox on your WinFrom, you drop your UserControl on the form.

Treat your UserControl just like you would treat any other control, like TextBox or ListBox.

So, just like you get the value from a TextBox through TextBox.Text or the SelectedValue or SelectedItem from a ListBox, you would call a method from your UserControl to return the SelectedItem.

Often times when the OK button is clicked or the form is closed is when in your code you would go through each of your form's controls getting their values. Presumably, you would do some validation to make sure proper values were entered, too.

Therefore, when your form is accepted is when you would call your UserControl's method to get the selected item. You don't have to subscribe to an event to wait for that to happen. Again, just treat it like you would treat a normal ListBox.

EDIT:

Knowing now more about the nature of your question this is my answer:

Say you have a UserControl that looks like this:

In the code behind you are going to have to set up an Event to monitor when the the OK button has been clicked inside the UserControl. This event will also notify a subscriber what the choice was that the user selected in your list:

public partial class SelectFromListUserControl : UserControl
{
    public class SelectedItemEventArgs : EventArgs
    {
        public string SelectedChoice { get; set; }
    }

    public event EventHandler<SelectedItemEventArgs> ItemHasBeenSelected;

    public SelectFromListUserControl()
    {
        InitializeComponent();
    }

    private void btnOK_Click(object sender, EventArgs e)
    {
        var handler = ItemHasBeenSelected;
        if (handler != null)
        {
            handler(this, new SelectedItemEventArgs 
                { SelectedChoice = listBox1.SelectedItem.ToString() });
        }
    }
}

On your main form you will have code patterned similar to the following.

  1. There should be a routine to create or make visible this special user control.
  2. It will hook the event in the user control so that the main form will be notified.
  3. It will draw the user control.
  4. The event handler will retrieve the value selected in the user control and then clear the user control and/or bring up another user control.

    private void ShowSelectFromListWidget()
    {
        var uc = new SelectFromListUserControl();
        uc.ItemHasBeenSelected += uc_ItemHasBeenSelected;
    
        MakeUserControlPrimaryWindow(uc);
    }
    
    void uc_ItemHasBeenSelected(object sender, 
                         SelectFromListUserControl.SelectedItemEventArgs e)
    {
        var value = e.SelectedChoice;
    
        ClosePrimaryUserControl();
    }
    
    private void MakeUserControlPrimaryWindow(UserControl uc)
    {
        // my example just puts in in a panel, but for you
        // put your special code here to handle your user control management 
        panel1.Controls.Add(uc);
    }
    
    private void ClosePrimaryUserControl()
    {
        // put your special code here to handle your user control management 
        panel1.Controls.Clear();
    }
    


回答2:

Embed it in a form and call the form modally (ShowDialog)?



回答3:

But how can I make it wait until user performs the required action with the control?

The question is more about how to wait for the user to select item and click OK button without blocking entire user interface.

The answer is simple: Async/Await feature.

private readonly SelectCompletionSource as new TaskCompletionSource(of ResultType)

public async function SelectItemAsync() as ResultType

    me.Visible = true

    return await SelectComplectionSource.Task
end function

public function OK() as boolean

    me.Visible = false

    dim Result = me.SelectedItem

    SelectComplectionSource.
        SetResult(Result)
end function

To get an Item one calls

dim Item = await UserControl.SelectItemAsync

UserControl is shown to the user without blocking user interface. The selection task is started but paused until the result is ready.

By clicking OK button, user invokes OK function that queries selected item and makes selection task into completed state.