0

I'm making an app for Windows 10 Mobile Enterprise using the UWP frameworks. I have a number of files to save to disk in a loop, and I want to show a popup ProgressBar that blocks the user while the files are being saved. I want to update the ProgressBar every loop iteration, and remove it at the end.

I figured I could make a custom ContentDialog containing a ProgressBar, and show the ContentDialog at the start. I'm confused how to do this though, because the ContentDialog's ShowAsync() method blocks while dialog is open.

My guess is that I must either do the ShowAsync() or the file loop in a new thread/task/whatever. Is there a best practices sort of approach for this?

Note - the progress bar cannot, according to the requirements just go inside the current page. It has to be a popup of some sort that blocks the user until it is closed by the code.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
tj94
  • 61
  • 7

2 Answers2

1

ContentDialog is actually not really suitable for this scenario. The problem is that ContentDialog represents a modal dialog, which means the app window is blocked until the dialog is closed by the user. The Task ShowAsync() method is built in such way that you can wait for the user to perform the content dialog action and you cannot open the dialog on any other thread than UI.

You have three possible solutions:

  • Add a kind of "status bar" into your app, that will indicate an action is in progress and when the user clicks it, show a Popup with progress details (which can be dismissed by clicking elsewhere, but the user is able to show it again from the "status bar")
  • Implement a Secondary view, which will show the progress of the operation. You can find more information on Secondary views in the documentation. Also note that the secondary view has a different UI thread, so you will have to keep that in mind when updating its UI (you will have to use that view's Dispatcher)
  • Create some a "fake window" within your app, which will be just a UI element above all other UI. This will however not feel right, so I would suggest against this approach.
Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • I've been experimenting with option #2, and it seems to be working fantastically! However I do have one more question - is there a way to make the new window appear above the old, so that you can see the old behind the new? At the moment my new page takes up the entire screen, even when I set it to have a small width/height and a transparent background. – tj94 Mar 28 '18 at 04:10
  • `ShowAsync` is not blocking. Just **do not** use `await` and then run as much code as you like while the dialog is open. The problem however is that the user can back out of the dialog with the back button or Escape key. Why not just show the progress bar and disable / hide all the controls on the pages? – Peter Torr - MSFT Mar 28 '18 at 05:11
  • @PeterTorr-MSFT I didn't mean that `ShowAsync` is literally blocking, but it is blocking user input on the page while the dialog is open. From what I understood, the OP wanted to be able to show progress in the dialog while still being able to interact with the app normally and that won't be possible with `ContentDialog` as far as I know. – Martin Zikmund Mar 28 '18 at 06:00
  • @tj94 It should be possible to set the new app view to a specific size. Try the approaches in this SO question - https://stackoverflow.com/questions/31885979/windows-10-uwp-app-setting-window-size-on-desktop – Martin Zikmund Mar 28 '18 at 06:02
  • @MartinZikmund, what I actually wanted was for the content dialog to appear in front of the main UI. The main UI should NOT be interactable with by the user, but I need some code to still execute while the dialog is open. The dialog would then be closed programmatically when the code is finished. The user cannot close this dialog, or interact with the main UI in any way until the code has finished. – tj94 Mar 28 '18 at 09:50
  • In that case @Peter Torr is correct, but there is no way to make the `ContentDialog` uncloseable, so I would suggest adding a semitransparent UI element above the page contents to disable it. Also custom UI will allow you to make sure user cannot close it until you actually hide it. – Martin Zikmund Mar 28 '18 at 09:53
  • If I just make the ContentDialog buttonless, the user could only close it via the hardware Back button, correct? (btw the phone in question has no hardware keyboard, so no Escape key). Is it possible to disable the hard Back button in software? – tj94 Mar 28 '18 at 11:40
  • 1
    No, you can't disable it. Just disabling the controls and optionally showing your own simple fake dialog is best. – Peter Torr - MSFT Mar 28 '18 at 15:57
  • 1
    Okay, I've got it all sorted now. I've gone with a normally hidden control that has a ZIndex higher than everything else, and I show it and disable the whole page when I want to show the progress. Thanks for the advice! – tj94 Mar 29 '18 at 00:16
0

A late reply but if anyone run into this in the future another potential solution is to just block the rest of the page with your progress bar. If the contents of your view are contained in a single grid, you can place the progress bar as the last element in the grid which causes it to be presented on top of all the other UI elements. You will likely have to wrap the ProgressBar with it's own Grid so that you can center the ProgressBar on the page, but use the grid to overlay and effectively disable the rest of the page while the ProgressBar is running.

I do something similar with loading rings in my apps:

<Grid
    Grid.ColumnSpan="3"
    Background="Black"
    Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource VisibleWhenTrueConverter}}"
    Opacity="0.6">
    <ProgressRing
        Width="100"
        Height="100"
        IsActive="{x:Bind ViewModel.IsLoading}" />
</Grid>
P-Day
  • 1
  • 1