简体   繁体   中英

Show listview in middle of method but wait until SelectionChanged event fires before method continues

Windows UWP app in C#. I have a method that checks a condition and depending on the condition, it may need to show a listview to the user so they can select an item from the list. I have more code in the method, after I potentially show the list view that needs to run after. However, because the listview shows and I have to wait for the SelectionChanged event handler to fire, I cannot figure out how to pause the calling method on that line until the event handler is completed for SelectionChanged. I don't have code written yet, so here is some pseduo code to illustrate:

private void LookupEmployee(string searchCriteria)
{
     List<string> matches = GetEmployeeNameMatchesFromCriteria(searchCriteria);

     if(matches.Count == null || matches.Count == 0)
     {
         //No matches found, warn user
         return;
     }
     if(matches.Count == 1)
     {
         //We are good, we have just one match which is desirable.
     }
     if(matches.Count > 1)
     {
         //This means we have more than one match and we need to popup list view to have user select one
         ShowListView(matches);
     }

     //Process Employee data here.
}

I know one option is to "daisy chain" calls by breaking out the final processing of employee data to another method and call that from the event handler for SelectionChanged of the listview. However, this has two issues. First, if I just have one match, then I will not be showing the listview or getting the SelectionChanged anyway. Second, if I had a bunch of variables and other things at the beginning of the method to be used at the end of the method, I don't want to (nor do I know how to) pass all of that through and back from the event handler in the event I need to show it.

I guess what I am looking for in a way is how the MessageDialog is handled.

 var md = new MessageDialog("My Message");

 md.Commands.Add(new UICommand("Okay")
 {

 });

 var result = await md.ShowAsync();

 if (result.Label == "Okay")
 {
     DoStuff;
 }

Where using this will wait on the line:

await md.ShowAsync();

Until the user clicks the button, at which point the method can continue from there.

I guess I am looking for something similar to that where I can hold on the line of the method in the case that I need to show the listview until the user selects and item and grab the item that was selected.

Thoughts?

Thanks!

Okay, I think I found what I was looking for so I wanted to post the code. This is similar to how a modal window worked in the old days. Basically, you can use a ContentDialog which will allow you to "wrap" any controls you want in it. In my case, I want to show a ListView, so I wrap that in the ContentDialog. Here is what I have:

  1. First we can do our tests and based on the tests, we can create the ContentDialog/ListView if needed. If we do create the ContentDialog, we can also setup the Display parameters so it fits the way we want it to.

     private async void checkProductMatches() { var selectedItem = string.Empty; //Check our results from DB. if (productResults.Count == 0) { //This means we didn't find any matches, show message dialog } if (productResults.Count == 1) { //We found one match, this is ideal. Continue processing. selectedItem = productResults.FirstOrDefault().Name; } if (productResults.Count > 1) { //Multiple matches, need to show ListView so they can select one. var myList = new ListView { ItemTemplate = Create(), ItemsSource = productResults, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }; var bounds = Window.Current.Bounds; var height = bounds.Height; var scroll = new ScrollViewer() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Height = height - 100 }; var grid = new StackPanel(); grid.Children.Add(myList); scroll.Content = grid; var dialog = new ContentDialog { Title = "Title", Content = scroll }; 
  2. Now, we wire up the event handler for the ListView SelectionChanged event and grab the selectedItem should this event raise.

      myList.SelectionChanged += delegate (object o, SelectionChangedEventArgs args) { if (args.AddedItems.Count > 0) { MyProducts selection = args.AddedItems[0] as MyProducts; if (selection != null) { selectedItem = selection.Name; } } dialog.Hide(); }; 
  3. Finally, we await the showing of the ContentDialog.

      var s = await dialog.ShowAsync(); 

What this will do is, if we have one item, there is no need to popup the content dialog. So, we can assign the one result to our selectedItem variable and proceed. However, if we have multiple matches, we want to display a list for the user to select the one item. In this case, we create the ContentDialog, ListView and display parameters. They key is to wire up the event handler before we call to show the dialog and inside of the event handler, we make sure to cancel or close the dialog. Then we call to await the dialog showing. This will pause execution of this method on that line while the dialog is showing. Once the user selects an item, the event handler will raise, get the selected item and then close the dialog, which will then allow the method to continue execution from the awaited line.

Here is the full method:

    private async void checkProductMatches()
    {
        var selectedItem = string.Empty;

        //Check our results from DB.
        if (productResults.Count == 0)
        {
            //This means we didn't find any matches, show message dialog
        }
        if (productResults.Count == 1)
        {
            //We found one match, this is ideal. Continue processing.
            selectedItem = productResults.FirstOrDefault().Name;
        }
        if (productResults.Count > 1)
        {
            //Multiple matches, need to show ListView so they can select one.
            var myList = new ListView
            {
                ItemTemplate = Create(),
                ItemsSource =
                    productResults,
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    VerticalAlignment = VerticalAlignment.Stretch
            };

            var bounds = Window.Current.Bounds;
            var height = bounds.Height;
            var scroll = new ScrollViewer() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Height = height - 100 };

            var grid = new StackPanel();
            grid.Children.Add(myList);
            scroll.Content = grid;
            var dialog = new ContentDialog { Title = "Title", Content = scroll };

            myList.SelectionChanged += delegate (object o, SelectionChangedEventArgs args)
            {
                if (args.AddedItems.Count > 0)
                {
                    MyProducts selection = args.AddedItems[0] as MyProducts;
                    if (selection != null)
                    {
                        selectedItem = selection.Name;
                    }
                }
                dialog.Hide();
            };

            var s = await dialog.ShowAsync();
        }

        //Test furter execution. Ideally, selected item will either be the one record or we will 
        //get here after the list view allows user to select one.
        var stringTest = string.Format("Selected Item: {0}", selectedItem);
    }

Hope this helps someone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM