Germán Küber

Microsoft Architect

Universal Windows Platform (UWP) – Net Conf Ar

Repositorio

https://github.com/GermanKuber/ReadApp

Clonamos el repositorio con el proyecto base.

git clone https://github.com/GermanKuber/ReadApp.git

 

Edito el archivo MainPage.xaml

<Grid Background="#FFFFFF">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="320"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid Grid.Column="0">
        <Grid Background="#FF1D3F58">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="0*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <ListView x:Name="listView"    Grid.Row="1" Background="#FF1D3F58" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin">
            </ListView>
            <TextBox x:Name="textBox"  Margin="10,10,1,8" TextWrapping="Wrap"  d:LayoutOverrides="Height, LeftMargin, RightMargin, TopMargin, BottomMargin" PlaceholderText="Buscar ..." Background="#FF1D3F58" Foreground="White" SelectionHighlightColor="White" >
            </TextBox>
        </Grid>
    </Grid>
    <Grid Grid.Column="1"  Margin="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="13*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Grid.Column="0" BorderThickness="0,0,0,2"   >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Ellipse  Grid.Column="0" x:Name="Imangen" Margin="20 20 20 20" Stroke="Black" HorizontalAlignment="Right" Width="150" Height="150" >
            </Ellipse>
            <StackPanel Grid.Column="1"   VerticalAlignment="Center" Margin="0 30 0 0"  >
                <TextBlock Text="Descripción"  TextWrapping="Wrap" ></TextBlock>
                <TextBlock  TextWrapping="Wrap" ></TextBlock>
            </StackPanel>
        </Grid >
        <ScrollViewer  x:Name="scrollViewer" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,-0.333,0,0" Background="#B29E9494" >
        </ScrollViewer>
        <Grid Grid.RowSpan="2"/>
    </Grid>
</Grid>

Tras agregar este código en el archivo MainPage.xaml, podemos presionar sobre ejecutar (o F5) y vamos a observar una ventana como esta:

 

03 – Bindings

En el archivo MainPage.xaml agrego

<Page.DataContext>
    <viewModels:MainPageDataViewModel />
</Page.DataContext>

Ahora vamos a agregar en nuestra clase MainPageDataViewModel (la cual contendrá toda la lógica de nuestra aplicación)

 //TODO : 04 - Implemento la interface INotifyPropertyChanged
public class MainPageDataViewModel : INotifyPropertyChanged
{
    //implemento la propiead de la interface.
    public event PropertyChangedEventHandler PropertyChanged;

    public MainPageDateService MainPageDateService = new MainPageDateService();

    private ReadRepository _readRepository = new ReadRepository();

    public ConfigurationsViewModel Configuration = new ConfigurationsViewModel();

    #region Public Properties

    //TODO : 03 - Agrego una lista observable, para derectar los cambios en la view
    public ObservableCollection<CommunityModel> ReadModels { get; set; } = new ObservableCollection<CommunityModel>();

    //TODO : 05 - Propiedad que se utilizara bindear contra el item seleccionado
    private CommunityModel _selectedRead;
    public CommunityModel SelectedRead
    {
        get { return _selectedRead; }
        set
        {
            _selectedRead = value;

            PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(nameof(SelectedRead)));

        }
    }
    //TODO : 06 - Agrego propiedad para  bindear contra el texto que el usuario filtra
    private string _filter;
    public string Filter
    {
        get { return _filter; }
        set
        {
            if (value == _filter)
                return;

            _filter = value;
            PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(nameof(Filter)));

            FilterTextAsync();
        }
    }


    #endregion


    #region Commands

    //private ICommand _exampleCommand;
    //public ICommand ExampleCommand
    //{
    //    get
    //    {
    //        if (_exampleCommand == null)
    //        {
    //            _exampleCommand = new CommandHandler(((obj) =>
    //            {
    //                ...
    //            }));
    //        }
    //        return _exampleCommand;
    //    }
    //    set { _exampleCommand = value; }
    //}

    #endregion


    #region Private Properties



    #endregion


    #region Constructor

    public MainPageDataViewModel()
    {

        GenerateDummyData();
    }

    #endregion

    #region Private Methods

    //TODO : 07 - Agrego metodo para filtrar y cargar los modelos a la lista
    private async Task FilterTextAsync()
    {
        if (_filter == null)
            _filter = "";

        //Se filtran los readModels por Name
        var result = await _readRepository.GetByNameAsync(this.Filter);

        ReadModels.Clear();
        result.ForEach(x =>
        {
            ReadModels.Add(x);
        });
        if (ReadModels.Count > 0)
            this.SelectedRead = ReadModels.First();
    }

    #endregion

    private void GenerateDummyData()
    {

        var list = _readRepository.DataForView();
        
        ReadModels.Clear();

        list.ForEach(x =>
        {
            ReadModels.Add(x);
            
        });

        if (ReadModels != null && ReadModels.Count > 0)
            this.SelectedRead = ReadModels.First();
    }

}

Ahora remplazo el primer TextBock y el primer ListView con el siguiente código:

<ListView x:Name="listView" ItemTemplate="{StaticResource RememberModelTemplate}"  ItemsSource="{Binding ReadModels}" Grid.Row="1" SelectedItem="{Binding SelectedRead, Mode=TwoWay}" Background="#FF1D3F58" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin">
</ListView>
<TextBox x:Name="textBox" Text="{Binding Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,1,8" TextWrapping="Wrap"  d:LayoutOverrides="Height, LeftMargin, RightMargin, TopMargin, BottomMargin" PlaceholderText="Buscar ..." Background="#FF1D3F58" Foreground="White" SelectionHighlightColor="White" >
</TextBox>

Remplazo el Ellipse y el StackPanel

<Ellipse  Grid.Column="0" x:Name="Imangen" Margin="20 20 20 20" Stroke="Black" d:LayoutOverrides="TopPosition, BottomPosition" HorizontalAlignment="Right" Width="150" Height="150" >
    <Ellipse.Fill>
        <ImageBrush Stretch="Fill" ImageSource="{Binding SelectedRead.Picture}"/>
    </Ellipse.Fill>
</Ellipse>
<StackPanel Grid.Column="1"   VerticalAlignment="Center" Margin="0 30 0 0"  >
    <TextBlock Text="Descripción"  TextWrapping="Wrap" ></TextBlock>
    <TextBlock Text="{Binding SelectedRead.Description}" TextWrapping="Wrap" ></TextBlock>
</StackPanel>

Por ultimo remplazo el ultimo ScrollViewer  por

<ScrollViewer  x:Name="scrollViewer" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,-0.333,0,0" d:LayoutOverrides="TopPosition, BottomPosition">
    <ItemsControl ItemTemplate="{StaticResource ReadEventsTemplate}" ItemsSource="{Binding SelectedRead.Events}">
    </ItemsControl>
</ScrollViewer>

A continuación deberíamos de ver lo siguiente:

 

04 – Other Features

Reemplazo los dos AppBarButton con el siguiente código

<AppBarButton 
    Command="{Binding DataContext.SendEmailCommand, ElementName=GridContext}"
        CommandParameter="{Binding}"   
x:Name="btnEmail" Content="Button" Icon="Mail" Height="54" HorizontalAlignment="Left" Margin="350,49,0,0" Label="Email" FontSize="19" d:LayoutOverrides="VerticalAlignment" Visibility="{Binding EmailVisibility, Mode=OneWay}"/>
<AppBarButton  
        Command="{Binding DataContext.AddNoticeToCommand, ElementName=GridContext}"
        CommandParameter="{Binding}"   
        x:Name="btnCalendar" Content="Button" Icon="Calendar" Height="50" HorizontalAlignment="Left" d:LayoutOverrides="VerticalAlignment" Margin="430,50,0,0" />

Agrego los comandos correspondientes al MainPageDataViewModel

private ICommand _addNoticeToCommand;
public ICommand AddNoticeToCommand
{
    get
    {
        if (_addNoticeToCommand == null)
        {
            _addNoticeToCommand = new CommandHandler(((obj) =>
            {
                MainPageDateService.AddNoticeToCalendarAsync((EventModel)obj);
            }));
        }
        return _addNoticeToCommand;
    }
    set { _addNoticeToCommand = value; }
}

private ICommand _sendEmailCommand;
public ICommand SendEmailCommand
{
    get
    {
        if (_sendEmailCommand == null)
        {
            _sendEmailCommand = new CommandHandler((async (obj) =>
            {
                await MainPageDateService.SendEmailAsync((EventModel)obj, SelectedRead.Email);
            }));
        }
        return _sendEmailCommand;
    }
    set { _sendEmailCommand = value; }
}

 

Modifico el constructor de MainPageDataViewModel

public MainPageDataViewModel()
{
    if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
        GenerateDummyData();
    else
        FilterTextAsync();

    this.Configurations = new ConfigurationsViewModel();
}

 

Agrego los comandos para configuración y navegación en MainPage.xaml

<Page.BottomAppBar>
    <CommandBar x:Name="commandBar" Margin="0,17,0,0" RenderTransformOrigin="0.5,0.5" >
        <CommandBar.SecondaryCommands>
            <AppBarToggleButton x:Name="appBarToggleButton" Label="Notificaciones" IsChecked="{Binding Configurations.NotificationsEnabled, Mode=TwoWay}" DataContext="{Binding}"/>
            <AppBarToggleButton x:Name="appBarToggleButton1" Label="Live" IsChecked="{Binding Configurations.LiveTileEnabled, Mode=TwoWay}" DataContext="{Binding}"/>
            <AppBarToggleButton x:Name="appBarToggleButton2" Label="Dark Theme" IsChecked="{Binding Configurations.DarkTheme, Mode=TwoWay}" DataContext="{Binding}"/>
            <AppBarSeparator/>
            <AppBarToggleButton x:Name="appBarButton" Label="About" Click="appBarButton_Click"/>
        </CommandBar.SecondaryCommands>
        <CommandBar.Content>
            <Grid/>
        </CommandBar.Content>
    </CommandBar>
</Page.BottomAppBar>

Agrego el código para manejar el click de appBarButton en MainPage.xaml.cs

private void appBarButton_Click(object sender, RoutedEventArgs e)
{
    //TODO : 07 - Boton de navegación
    Frame.Navigate(typeof(About));
}

 

Ahora vamos a registrar un servicio background que se encargue de generar las notificaciones y el live, para eso vamos al archivo App.xaml.cs y en el evento OnLaunched agregamos el siguiente código.

ReadAppBackgroundTask.Register();

Luego nos dirigimos al  Package.appxmanifest

Y vamos a registrar nuestra clase para que sea el punto de entrada de esta tarea en background. Además debemos de dar los siguientes accesos.

Una vez que realizamos estos pasos, vamos a ejecutar nuestra aplicación. Con ella ejecutada vamos a ejecutar nuestra tarea en background de la siguiente forma.

 

Una vez mas nos dirigimos al App.xaml.cs y en el evento OnLaunched agregamos el siguiente código.

var vcdFile = await StorageFile.GetFileFromApplicationUriAsync(
        new Uri("ms-appx:///VoiceCommandDefinition.xml"));

await
    VoiceCommandDefinitionManager
        .InstallCommandDefinitionsFromStorageFileAsync(vcdFile);

Este código registrara el comando de Cortana.

Ahora en vamos a sobre escribir el método  OnActivated

protected override void OnActivated(IActivatedEventArgs args)
{
    base.OnActivated(args);
    //TODO : 09 - Se configura para responder a la activación mediante voicecommand
    if (args.Kind == ActivationKind.VoiceCommand)
    {
        //The app was invoked via a voice command.
    }

    if (Window.Current.Content == null)
    {
        var rootFrame = new Frame();
        rootFrame.NavigationFailed += OnNavigationFailed;
        Window.Current.Content = rootFrame;
        rootFrame.Navigate(typeof(MainPage));
        Window.Current.Activate();
    }
}

Y por ultimo vamos a registrar el servicio al igual que lo hicimos con nuestro background service

 

Ahora solo nos queda hablar con Cortana

    

 

05 – Behaviors

Vamos agregarle una pequeña transicion al momento de cargar a la lista de eventos para eso, nos dirigimos al MainPage.xaml, y vamos a editar el ScrolView que carga los eventos, y agregar un TransitionCollection

<ScrollViewer  x:Name="scrollViewer" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,-0.333,0,0" d:LayoutOverrides="TopPosition, BottomPosition">
    <ItemsControl ItemTemplate="{StaticResource ReadEventsTemplate}" ItemsSource="{Binding SelectedRead.Events}">
        <ItemsControl.ItemContainerTransitions>
            <TransitionCollection>
                <EntranceThemeTransition FromVerticalOffset="0" FromHorizontalOffset="200" IsStaggeringEnabled="True"/>
            </TransitionCollection>
        </ItemsControl.ItemContainerTransitions>
    </ItemsControl>
</ScrollViewer>

Ahora vamos a agregar un VisualState, donde generemos un state, para el loading. Continuando en el mismo archivo vamos a pegar dentro del tag de nuestro Grid principal, el siguiente código:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="LoadingState">
        <VisualState x:Name="Loading">
            <Storyboard>
                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="stackPanel1" d:IsOptimized="True"/>
            </Storyboard>
        </VisualState>
        <VisualState x:Name="Loaded">
            <Storyboard>
                <DoubleAnimation Duration="0:0:1" To="-550" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.GlobalOffsetY)" Storyboard.TargetName="textBlock1" d:IsOptimized="True">
                    <DoubleAnimation.EasingFunction>
                        <BackEase Amplitude="0.2" EasingMode="EaseIn"/>
                    </DoubleAnimation.EasingFunction>
                </DoubleAnimation>
                <DoubleAnimation Duration="0:0:0.494" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="progressBar" d:IsOptimized="True"/>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ProgressBar.IsIndeterminate)" Storyboard.TargetName="progressBar">
                    <DiscreteObjectKeyFrame KeyTime="0:0:0.494">
                        <DiscreteObjectKeyFrame.Value>
                            <x:Boolean>False</x:Boolean>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
                <DoubleAnimation Duration="0:0:1" To="0.4" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="textBlock1" d:IsOptimized="True"/>
                <DoubleAnimation Duration="0:0:1" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grid">
                    <DiscreteObjectKeyFrame KeyTime="0:0:1">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Canvas.ZIndex)" Storyboard.TargetName="grid">
                    <DiscreteObjectKeyFrame KeyTime="0:0:1">
                        <DiscreteObjectKeyFrame.Value>
                            <x:Int32>0</x:Int32>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
                <DoubleAnimation Duration="0:0:1" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="commandBar" d:IsOptimized="True">
                    <DoubleAnimation.EasingFunction>
                        <CircleEase EasingMode="EaseOut"/>
                    </DoubleAnimation.EasingFunction>
                </DoubleAnimation>
            </Storyboard>
        </VisualState>
        <VisualState x:Name="Error">
            <VisualState.Setters>
                <Setter Target="textBlock1.(TextBlock.FontWeight)">
                    <Setter.Value>
                        <FontWeight>Bold</FontWeight>
                    </Setter.Value>
                </Setter>
                <Setter Target="textBlock1.(TextBlock.Text)" Value="Ocurrio un Error!!"/>
            </VisualState.Setters>
            <Storyboard>
                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="stackPanel1" d:IsOptimized="True"/>
                <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="progressBar" d:IsOptimized="True"/>
                <ColorAnimation Duration="0" To="#FF931616" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="textBlock1" d:IsOptimized="True"/>
            </Storyboard>
        </VisualState>
    </VisualStateGroup>
    <VisualStateGroup x:Name="ScrenStates">
        <VisualState x:Name="Big">
            <VisualState.Setters>
                <Setter Target="splitView.(SplitView.IsPaneOpen)" Value="True"/>
                <Setter Target="splitView.(SplitView.DisplayMode)" Value="Inline"/>
            </VisualState.Setters>
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="1150"/>
            </VisualState.StateTriggers>
        </VisualState>
        <VisualState x:Name="Small">
            <VisualState.Setters>
                <Setter Target="splitView.(SplitView.DisplayMode)" Value="Overlay"/>
            </VisualState.Setters>
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0"/>
            </VisualState.StateTriggers>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Remplazamos  todo el contenido de nuestro grid y a la altura del VisualStateManager

<SplitView x:Name="splitView" BorderThickness="0" Grid.ColumnSpan="2" DisplayMode="Inline" IsPaneOpen="{Binding OpenMenu, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <SplitView.Pane>
        <Grid Grid.Column="0">
            <Grid Background="#FF1D3F58">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition Width="0*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="50"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <ListView x:Name="listView" ItemTemplate="{StaticResource RememberModelTemplate}"  ItemsSource="{Binding ReadModels}" Grid.Row="1" SelectedItem="{Binding SelectedRead, Mode=TwoWay}" Background="#FF1D3F58" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin">
                </ListView>
                <TextBox x:Name="textBox" Text="{Binding Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,1,8" TextWrapping="Wrap"  d:LayoutOverrides="Height, LeftMargin, RightMargin, TopMargin, BottomMargin" PlaceholderText="Buscar ..." Background="#FF1D3F58" Foreground="White" SelectionHighlightColor="White">
                </TextBox>
            </Grid>
        </Grid>
    </SplitView.Pane>
    <Grid Grid.Column="1"  Margin="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="13*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Grid.Column="0" BorderThickness="0,0,0,2"   >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Ellipse  Grid.Column="0" x:Name="Imangen" Margin="20 20 20 20" Stroke="Black" d:LayoutOverrides="TopPosition, BottomPosition" HorizontalAlignment="Right" Width="150" Height="150" >
                <Ellipse.Fill>
                    <ImageBrush Stretch="Fill" ImageSource="{Binding SelectedRead.Picture}"/>
                </Ellipse.Fill>
            </Ellipse>
            <StackPanel x:Name="stackPanel1" Grid.Column="1"   VerticalAlignment="Center" Margin="0 30 0 0"  >
                <TextBlock Text="Descripción"  TextWrapping="Wrap" ></TextBlock>
                <TextBlock Text="{Binding SelectedRead.Description}" TextWrapping="Wrap" ></TextBlock>
            </StackPanel>
        </Grid >
        <ScrollViewer  x:Name="scrollViewer" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,-0.333,0,0" d:LayoutOverrides="TopPosition, BottomPosition">
            <ItemsControl ItemTemplate="{StaticResource ReadEventsTemplate}" ItemsSource="{Binding SelectedRead.Events}">
                <ItemsControl.ItemContainerTransitions>
                    <TransitionCollection>
                        <EntranceThemeTransition FromVerticalOffset="0" FromHorizontalOffset="200" IsStaggeringEnabled="True"/>
                    </TransitionCollection>
                </ItemsControl.ItemContainerTransitions>
            </ItemsControl>
        </ScrollViewer>
        <Grid Grid.RowSpan="2"/>
    </Grid>
</SplitView>

También vamos a descomentar la siguiente linea de código

<AppBarButton x:Name="appBarButton1" HorizontalAlignment="Stretch" Icon="AlignCenter" Label="Menu" VerticalAlignment="Stretch" d:LayoutOverrides="Height" Command="{Binding SwitchMenuCommand}" ></AppBarButton>

Descomentamos todo el código que tengo en el MainPage.xaml.cs, el cual se encargara de administrar el cambio de states

Volviendo al archivo  MainPageDataViewModel.cs vamos a agregar el comando necesario para administrar la apertura y cierre del menú.

private bool _openMenu;
public bool OpenMenu
{
    get { return _openMenu; }
    set
    {
        _openMenu = value;
        PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(nameof(OpenMenu)));
    }
}

private ICommand _switchMenuCommand;

public ICommand SwitchMenuCommand
{
    get
    {
        if (_switchMenuCommand == null)
        {
            _switchMenuCommand = new CommandHandler(((obj) =>
            {
                this.OpenMenu = !this.OpenMenu;
            }));
        }
        return _switchMenuCommand;
    }
    set { _switchMenuCommand = value; }
}

 

Ahora vamos a agregar la pantalla de Loading. Para eso tomamos el siguiente código y lo vamos a poner dentro del grid principal, como hermano del splitview.

<Grid x:Name="grid" d:LayoutOverrides="LeftPosition, RightPosition, TopPosition, BottomPosition" Grid.ColumnSpan="2" Background="#FF2E2E2E" Opacity="0.9" Canvas.ZIndex="1" d:IsHidden="True">
    <StackPanel x:Name="stackPanel1" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center">
        <TextBlock x:Name="textBlock1" Style="{StaticResource HeaderTextBlockStyle}" TextWrapping="Wrap" Text="Cargando ...">
            <TextBlock.Projection>
                <PlaneProjection/>
            </TextBlock.Projection>
        </TextBlock>
        <ProgressBar x:Name="progressBar" Height="10" VerticalAlignment="Stretch" IsIndeterminate="True" Margin="0,8,0,0" FontSize="22"/>
    </StackPanel>
</Grid>

 

 

Generar Assets

Descargo el Assets Generator

https://marketplace.visualstudio.com/items?itemName=PeterR.UWPVisualAssetsGenerator

Editamos el package.appxmanifest

 

Slides

[slideshare id=77582814&doc=netconfarv2017template-170706161222]

Translate »