2

Is it possible to create a modal (asynchronous) dialog in a Windows Store App with custom content?

I know you can show a Message Dialog but only with some text and buttons. In my App I need to populate a Combo Box and let the user choose one of the items, before the rest of the code can be executed.

I already found something for a dialog which is not asynchronous (code is appended). It worked quite well until now.
However, now I need to check again with the user if the chosen device is okay and somehow the Message Dialog is shown above the Dialog with the Combo Box.

Is there a (simple) way to "wait" for the result of my first Dialog?


Here the code of the custom popup I am using for my ComboBox Dialog:

public sealed partial class UsbSelectorPopup : UserControl {

    public IList<DeviceInformation> deviceList { get; set; }
    public int ChosenEntry { get; set; }

    public UsbSelectorPopup(IList<DeviceInformation> deviceList) {
        this.InitializeComponent();
        this.deviceList = deviceList;
        PopulateComboBox();
    }

    private void PopulateComboBox() {
        ...
    }

    public void OpenPopup() {
        this.ParentPopup.IsOpen = true;
        this.gdChild.Visibility = Visibility.Visible;
    }

    public void ClosePopup() {
        this.ParentPopup.IsOpen = false;
        this.gdChild.Visibility = Visibility.Collapsed;
    }

    private void ChooseUsbBtn_Click(object sender, RoutedEventArgs e) {
        ChosenEntry = UsbComboBox.SelectedIndex;
        ClosePopup();
    }

    private void CloseUsbBtn_Click(object sender, RoutedEventArgs e) {
        ChosenEntry = 9999;
        ClosePopup();
    }

The Call in the MainPage:

// get all the USB Devices
var devices = ExamProvider.CustomStorageMedium.DeviceCollection;

// ask user which usb device to use
UsbSelectorPopup popup = new UsbSelectorPopup(devices);
popup.OpenPopup();

// get chosen device out of list
var chosenDevice = devices[popup.ChosenEntry];

// work with data on usb stick
 [...]

// ask user if he wants to continue with this device or choose another one
var result = await MessageBox.ShowAsync("You chose usb stick XYZ with file ABC on it. Do you want to continue?", MessageBoxButton.OkCancel);

(MessageBox is a simple Helper Class for calling MessageDialog)

Solution

Thanks to Nate Diamond I knew what it was I should look for and so I found this answer: https://stackoverflow.com/a/12861824/2660864
I changed it a bit and surprisingly it now works!

UsbSelectorPopup:

// Property
public TaskCompletionSource<int> UsbChosenTask { get; set; }

// in the constructor:
UsbChosenTask = new TaskCompletionSource<int>();

// In the Button Click Methods:
UsbChosenTask.TrySetResult(UsbComboBox.SelectedIndex);

The call:

UsbSelectorPopup popup = new UsbSelectorPopup(devices);
popup.OpenPopup();
var chosenEntry = await popup.UsbChosenTask.Task;
var chosenDevice = devices[popup.ChosenEntry];
Community
  • 1
  • 1
katho2404
  • 359
  • 1
  • 6
  • 20
  • One easy way to do this is with `TaskCompletionSource`. What this lets you do is return a `Task` (can be Task) which only returns when you call `TaskCompletionSource.SetResult(T result)`. This means that you can do all of your asynchronous processes and set the result (or set cancel/error) when you are done processing. – Nate Diamond May 05 '14 at 21:16
  • thanks for your comment. is it possible to provide an example how I can use the Tasks with my existing code? I already tried a bit but I don't have much experience with asynchronicity so I don't know exactly how I should approach my problem. – katho2404 May 06 '14 at 08:26
  • @NateDiamond you can add an answer if you like, I would accept it – katho2404 May 06 '14 at 09:09

2 Answers2

4

XAML has a popup control that is what you want.

<Popup x:Name="popup" IsOpen="True">
    <Grid Width="{Binding ActualWidth, ElementName=popup, Mode=OneWay}" 
            Height="{Binding ActualHeight, ElementName=popup, Mode=OneWay}">
        <!-- your content here -->
        <Rectangle Fill="Red" Opacity=".25" />
    </Grid>
</Popup>

In your code behind you can cause it to open and close by toggling the IsOpen property.

Make sense?

Best of luck.

Jerry Nixon
  • 31,313
  • 14
  • 117
  • 233
  • hey, thanks for your answer. I already have the popup tag in my xaml. The main problem was, that I could not await the result of the popup and the MessageDialog called after the popup showed before the user could input something. The answer from Nate Diamond solved this problem. – katho2404 May 07 '14 at 08:29
  • There's always AsTask().Wait() – Jerry Nixon May 09 '14 at 19:12
1

One easy way to do this is with TaskCompletionSource. What this lets you do is return a Task (can be Task) which only returns when you call TaskCompletionSource.SetResult(T result). This means that you can do all of your asynchronous processes and set the result (or set cancel/error) when you are done processing.

A quick example would be:

private TaskCompletionSource<bool> taskCompletionSource;

private Task<bool> ShowAsync()
{
    //Do Show Stuff

    taskCompletionSource = new TaskCompletionSource<bool>();

    return taskCompletionSource.Task;
}

private void Close()
{
    //Do close stuff

    taskCompletionSource.SetResult(true);
}
Nate Diamond
  • 5,525
  • 2
  • 31
  • 57