MessageDialog for IoT “UPDATE: Huston we have a problem”

The Windows.UI.Popups.MessageDialog is not working under the IoT Core platform. But what insane! If there’s the possibility to show a human interface, we must be able to interact with it. The MessageDialog is one of the most part for interact with Human Interface. The only thing that we can do is make ourselves our Message Dialog. Let’s see how.

The MessageDialog for UWP have a simple but functional view.

Dialog_1

This have the great behavior to work under PC, tablet, phone and all devices that runs Windows 10… all but IoT devices!

If our need is to show this dialog under IoT, we have no choice: we have to build it ourselves.

How do that? Simple!

Let’s start with a stack panel with vertical orientation, wich inside we’ll put three textblocks

<StackPanel Grid.ColumnSpan="2" Grid.RowSpan="3">
  <TextBlock x:Name="textBlockTitle" Text="Lorem Ipsum"/>
  <TextBlock x:Name="textBlockMessageHeader" Text="Lorem Ipsum" FontSize="24"/>
  <TextBlock x:Name="textBlockMessage" Text="Aliquam laoreet magna sit amet mauris iaculis ornare. Morbi iaculis vel elementum volupat." />
</StackPanel>

I’ve put the textBlockMessageHeader’s font size to 24 because this text is bigger than others.

Now let’s go with the grid below the StackPanel with inside three buttons like this:

Snippet

<Grid Grid.Column="1" Grid.RowSpan="3" Margin="0,0,20,20">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="33*"/>
        <ColumnDefinition Width="33*"/>
        <ColumnDefinition Width="33*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="121*"/>
        <RowDefinition Height="29*"/>
    </Grid.RowDefinitions>
    <Button x:Name="buttonYes" Grid.Row="1" Grid.Column="0" Content="Yes" Margin="2"/>
    <Button x:Name="buttonNo" Grid.Row="1" Grid.Column="1" Content="No" Margin="2"/>
    <Button x:Name="buttonCancel" Grid.Row="1" Grid.Column="2" Content="Cancel" Margin="2"/>
</Grid>

and the message is ready!

Now we have to make it works. I wrapped it in a user control and personally I use an MVVM architecture with Caliburn Micro in my apps that can be a very intensive and deep behavior that go out of the scope of this post. For simply make-it-works, the best thing is write in the code behind of the user control.

The final code seems like this

 

#region Enum
public enum DialogResult : byte
{
    Yes = 0,
    No,
    Cancel
}
 
        #endregion
 
        #region Properties
 
private bool isShown = false;
public bool IsShown
{
    get
    {
        return isShown;
    }
    set
    {
        isShown = value;
        OnNotifyPropertyChanged(nameof(IsShown));
    }
}
 
private DialogResult result = DialogResult.Cancel;
public DialogResult Result
{
    get
    {
        return result;
    }
    set
    {
        result = value;
        OnNotifyPropertyChanged(nameof(Result));
    }
}
 
        #endregion
 
public UserControl1()
{
    InitializeComponent();
    this.DataContext = this;
}
 
private void buttonYes_Click(object sender, RoutedEventArgs e)
{
    Result = DialogResult.Yes;
    IsShown = false;
}
 
private void buttonNo_Click(object sender, RoutedEventArgs e)
{
    Result = DialogResult.No;
    IsShown = false;
}
 
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
    Result = DialogResult.Cancel;
    IsShown = false;
}
 
public async Task<DialogResult> ShowDialog()
{
    return await Task.Run(() =>
    {
        IsShown = true;
        SpinWait.SpinUntil(() => !IsShown);
        return result;
    });
}
 
 
 
public event PropertyChangedEventHandler PropertyChanged;
 
private void OnNotifyPropertyChanged(string name)
{
    if (PropertyChanged != null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(name));
    }
}

I created a method that awaits a property “IsShown” will fall down. After that it can return the correct value.

This is a simple way to implement this, and it can upgrade the code and can make it better than this, but it can me a good starting point.

Stay tuned!

 UPDATE:

“Huston, we have a problem.”

With great enthusiasm I published the article but I didn’t tried really on UWP because my laptop was in management and I tried on Windows 7. If you try this example, it will not work on Raspberry with this error:

ErrThread

What is it??? Where??? When the property change is raised. And the error is similar to the old “CrossThreadExceprion” that we were aple to skip with some triks. But now is different. What’s happened?

The explain is simple. The reference to the View is lost because in the code of ShowDialog is inside a Task.Run(…) and this launch a new task loosing the corresponding view. How to fix it? There are lots of ways. The first is this:

public async Task<DialogResult> ShowDialog()
{
    IsShown = true;
    return await Task.Run(() =>
    {
        SpinWait.SpinUntil(() => !IsShown);
        return result;
    });
}

Take the line IsShown = true; and put it out of the Task.Run statement. In this manner it will fix the problem in the immediate. But if we’ll have a lot of things to do? And if we can’t take the instruction out of the task? And if we use Caliburn micro or other MVVM frameworks, what will happen???

The answer soon in another post, I’m working on it for build a clear example.

Stay tuned!