I would like to create a library behaving like the CaptureFileAsync method, i.e. on a method call it would open up a full screen page with standard back navigation and return result to the caller.
I want to be able to call it the same way CaptureFileAsync is called:
var dialog = new Library.Dialog();
var result = await dialog.Show();
In the Show
method I'm currently navigating to my own page and returning a Task
which can be awaited by the caller:
public Task<string> Show()
{
var task = new Task<string>(() => result);
var frame = ((Window.Current.Content) as Frame);
frame.Navigate(typeof(DialogPage));
return task;
}
I call task.Start()
when the dialog is being closed (either cancelled by navigating back or confirmed by pressing a button) which causes the result to be returned to the awaiting caller.
The problem is that when Frame.GoBack()
is called, a new instance of the previous page is created and the result gets returned to the old instance which is not displayed any more. This is not how CaptureFileAsync
works: in its case the same instance of the calling page is kept.
My question is: how can I display a page from my library without affecting the frame navigation and inadvertently causing a new instance of the calling page to be created?
You can put all your UI on a Popup.
Take a look at PopupHelper.
It abstracts all the ickines of using Popups and takes care of animation, disabling access to controls etc.
I had the same issue, and this is what I came up with:
XAML
<Grid x:Name="MainGrid"
Background="#7F000000">
<Grid Width="480" Height="180" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Black">
<StackPanel>
<TextBlock Text="Custom Capture!" Style="{StaticResource HeaderTextBlockStyle}" Margin="20"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="SaveButton" Content="Save" HorizontalAlignment="Center" Click="CloseButton_Click"/>
<Button x:Name="CloseButton" Content="Close" HorizontalAlignment="Center" Click="CloseButton_Click"/>
</StackPanel>
</StackPanel>
</Grid>
</Grid>
The Control
public sealed partial class CustomCaptureControl : UserControl
{
private StorageFile file;
private ManualResetEvent reset;
private Popup _mainPopup;
/// <summary>
///
/// </summary>
public CustomCaptureControl()
{
this.InitializeComponent();
Rect windowBounds = CoreWindow.GetForCurrentThread().Bounds;
this.MainGrid.Width = windowBounds.Width;
this.MainGrid.Height = windowBounds.Height;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public async Task<StorageFile> ShowAsync()
{
StorageFile file = await Task.Run(() => this.GetFile());
return file;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private async Task<StorageFile> GetFile()
{
//Launch Popup in UI thread
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
this._mainPopup = new Popup();
this._mainPopup.Child = this;
this._mainPopup.IsOpen = true;
});
//Await user input
await Task.Run(() => this.AwaitUserInput());
return this.file;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private Task AwaitUserInput()
{
return Task.Run(() =>
{
this.reset = new ManualResetEvent(false);
WaitHandle.WaitAll(new WaitHandle[] { this.reset });
});
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void CloseButton_Click(object sender, RoutedEventArgs e)
{
Uri fileURI = new Uri("ms-appx:///Assets/SomeFile.pdf");
this.file = await StorageFile.GetFileFromApplicationUriAsync(fileURI);
this.reset.Set();
this._mainPopup.IsOpen = false;
this._mainPopup = null;
}
}
Usage
CustomCaptureControl capture = new CustomCaptureControl();
StorageFile file = await capture.ShowAsync();