Estendere l'app desktop con componenti UWP moderni

Alcune esperienze di Windows (ad esempio una pagina dell'interfaccia utente abilitata per il tocco) devono essere eseguite all'interno di un contenitore di app. Se si desidera aggiungere queste esperienze, estendere l'applicazione desktop con progetti UWP e componenti Windows Runtime.

In molti casi è possibile chiamare le API di Windows Runtime direttamente dall'applicazione desktop, pertanto prima di continuare la lettura, vedere Migliorare per Windows.

Nota

Le funzionalità descritte in questo argomento richiedono che venga creato un pacchetto dell'app (con identità del pacchetto al momento del runtime). Sono incluse le app in pacchetto (vedere Creare un nuovo progetto per un'app desktop WinUI 3 in pacchetto) e le app in pacchetto con posizione esterna (vedere Concedere identità del pacchetto creando pacchetti con posizione esterna). Vedere anche Funzionalità che richiedono l'identità del pacchetto.

Innanzitutto configura la soluzione

Aggiungi uno o più componenti di runtime e progetti UWP alla tua soluzione.

Inizia con una soluzione che contiene un Progetto di creazione pacchetti per applicazioni Windows con un riferimento all'applicazione desktop.

Questa immagine mostra una soluzione di esempio.

Extend start project

Se la soluzione non contiene un progetto di creazione di pacchetti, vedi Creare un pacchetto dell'applicazione desktop con Visual Studio.

Configurare l'applicazione desktop

Assicurati che l'applicazione desktop includa riferimenti ai file necessari per chiamare le API di Windows Runtime.

A tale scopo, vedi Chiamare le API di Windows Runtime nelle app desktop.

Aggiungere un progetto UWP

Aggiungi un progetto App vuota (Universale di Windows) alla soluzione.

Qui compilerai un'interfaccia utente XAML moderna o userai API che vengono eseguite solo in un processo UWP.

Add new project

Nel progetto di creazione di pacchetti fai clic con il pulsante destro del mouse sul nodo Applicazioni e quindi fai clic su Aggiungi riferimento.

Add reference

Quindi, aggiungi un riferimento al progetto UWP.

Select UWP project

La soluzione avrà un aspetto simile al seguente:

Solution with UWP project

(Facoltativo) Aggiungere un componente Windows Runtime

Per eseguire alcuni scenari, è necessario aggiungere codice a un componente Windows Runtime.

runtime component app service

Quindi, dal progetto UWP aggiungi un riferimento al componente di runtime. La soluzione avrà un aspetto simile al seguente:

Runtime Component Reference

Compilare la soluzione

Compila la soluzione per assicurarti che non vengano visualizzati errori. Se vengono visualizzati errori, apri Gestione configurazione e verifica che i progetti siano destinati alla stessa piattaforma.

Config manager

Vediamo cosa puoi fare con i progetti UWP e i componenti di runtime.

Visualizzare un'interfaccia utente XAML moderna

Durante il flusso dell'applicazione, puoi incorporare le interfacce utente moderne basate su XAML nell'applicazione desktop. Queste interfacce utente sono naturalmente adattive a diverse risoluzioni e dimensioni dello schermo e supportano i moderni modelli interattivi, ad esempio il tocco e l'input penna.

Con poche righe di markup XAML, ad esempio, puoi concedere agli utenti efficaci funzionalità di visualizzazione correlate alla mappa.

Questa immagine mostra un'applicazione Windows Forms che apre un'interfaccia utente moderna basata su XAML che contiene un controllo mappa.

adaptive-design

Nota

Questo esempio mostra un'interfaccia utente XAML con l'aggiunta di un progetto UWP alla soluzione. Questo è l'approccio supportato stabile per visualizzare le interfacce utente XAML in un'applicazione desktop. L'alternativa a questo approccio consiste nell'aggiungere controlli XAML UWP direttamente all'applicazione desktop usando un'isola XAML. Le isole XAML sono attualmente disponibili come anteprima per sviluppatori. Ti invitiamo a provarli nel codice prototipo, ma per il momento ti consigliamo di non usarli nel codice di produzione. Queste API e controlli continueranno a evolversi e a stabilizzarsi nelle versioni future di Windows. Per altre informazioni sulle isole XAML, vedi Controlli UWP nelle applicazioni desktop

Pattern di progettazione

Per visualizzare un'interfaccia utente basata su XAML, esegui queste operazioni:

1️⃣ Configurare la soluzione

2️⃣ Creare un'interfaccia utente XAML

3️⃣ Aggiungere un'estensione del protocollo al progetto UWP

4️⃣ Avviare l'app UWP dall'app desktop

5️⃣ Nel progetto UWP, visualizzare la pagina desiderata

Configurare la soluzione

Per informazioni generali su come configurare la soluzione, vedere la sezione Configurare la soluzione come primo passo all'inizio di questa guida.

La soluzione avrà un aspetto simile al seguente:

XAML UI Solution

In questo esempio il progetto Windows Forms è denominato Landmarks e il progetto UWP che contiene l'interfaccia utente XAML è denominato MapUI.

Creare un'interfaccia utente XAML

Aggiungi un'interfaccia utente XAML al progetto UWP. Ecco il codice XAML per una mappa di base.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="12,20,12,14">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <maps:MapControl x:Name="myMap" Grid.Column="0" Width="500" Height="500"
                     ZoomLevel="{Binding ElementName=zoomSlider,Path=Value, Mode=TwoWay}"
                     Heading="{Binding ElementName=headingSlider,Path=Value, Mode=TwoWay}"
                     DesiredPitch="{Binding ElementName=desiredPitchSlider,Path=Value, Mode=TwoWay}"
                     HorizontalAlignment="Left"
                     MapServiceToken="<Your Key Goes Here" />
    <Grid Grid.Column="1" Margin="12">
        <StackPanel>
            <Slider Minimum="1" Maximum="20" Header="ZoomLevel" Name="zoomSlider" Value="17.5"/>
            <Slider Minimum="0" Maximum="360" Header="Heading" Name="headingSlider" Value="0"/>
            <Slider Minimum="0" Maximum="64" Header=" DesiredPitch" Name="desiredPitchSlider" Value="32"/>
        </StackPanel>
    </Grid>
</Grid>

Aggiungere un'estensione del protocollo

In Esplora soluzioni apri il file package.appxmanifest del progetto di creazione pacchetti nella soluzione e aggiungi questa estensione.

<Extensions>
  <uap:Extension Category="windows.protocol" Executable="MapUI.exe" EntryPoint="MapUI.App">
    <uap:Protocol Name="xamluidemo" />
  </uap:Extension>
</Extensions>

Assegna un nome al protocollo, specifica il nome del file eseguibile generato dal progetto UWP e il nome della classe del punto di ingresso.

Puoi anche aprire package.appxmanifest nella finestra di progettazione, scegliere la scheda Dichiarazioni e quindi aggiungere l'estensione.

declarations-tab

Nota

La mappa controlla il download dei dati da Internet in modo che se ne fai uso, dovrai aggiungere anche la funzionalità "client Internet" al manifesto.

Avviare l'app UWP

Prima di tutto, dall'applicazione desktop crea un Uri che include il nome del protocollo ed eventuali parametri da passare all'app UWP. Chiama quindi il metodo LaunchUriAsync.


private void Statue_Of_Liberty_Click(object sender, EventArgs e)
{
    ShowMap(40.689247, -74.044502);
}

private async void ShowMap(double lat, double lon)
{
    string str = "xamluidemo://";

    Uri uri = new Uri(str + "location?lat=" +
        lat.ToString() + "&?lon=" + lon.ToString());

    var success = await Windows.System.Launcher.LaunchUriAsync(uri);

}

Analizzare i parametri e visualizzare una pagina

Nella classe App del progetto UWP esegui l'override del gestore eventi OnActivated. Se l'app viene attivata dal protocollo, analizza i parametri e quindi apri la pagina desiderata.

protected override void OnActivated(Windows.ApplicationModel.Activation.IActivatedEventArgs e)
{
    if (e.Kind == ActivationKind.Protocol)
    {
        ProtocolActivatedEventArgs protocolArgs = (ProtocolActivatedEventArgs)e;
        Uri uri = protocolArgs.Uri;
        if (uri.Scheme == "xamluidemo")
        {
            Frame rootFrame = new Frame();
            Window.Current.Content = rootFrame;
            rootFrame.Navigate(typeof(MainPage), uri.Query);
            Window.Current.Activate();
        }
    }
}

Nel codice sottostante la pagina XAML esegui l'override del metodo OnNavigatedTo per usare i parametri passati nella pagina. In questo caso useremo la latitudine e la longitudine passate in questa pagina per mostrare una posizione su una mappa.

protected override void OnNavigatedTo(NavigationEventArgs e)
 {
     if (e.Parameter != null)
     {
         WwwFormUrlDecoder decoder = new WwwFormUrlDecoder(e.Parameter.ToString());

         double lat = Convert.ToDouble(decoder[0].Value);
         double lon = Convert.ToDouble(decoder[1].Value);

         BasicGeoposition pos = new BasicGeoposition();

         pos.Latitude = lat;
         pos.Longitude = lon;

         myMap.Center = new Geopoint(pos);

         myMap.Style = MapStyle.Aerial3D;

     }

     base.OnNavigatedTo(e);
 }

Rendere l'applicazione desktop una destinazione di condivisione

Puoi rendere la tua applicazione desktop una destinazione di condivisione in modo che gli utenti possano condividere facilmente dati come immagini da altre app che supportano la condivisione.

Ad esempio, gli utenti potrebbero scegliere la tua applicazione per condividere le immagini da Microsoft Edge, l'app Foto. Ecco un'applicazione WPF di esempio con questa funzionalità.

share target.

Vedi l'esempio completo qui

Pattern di progettazione

Per rendere l'applicazione una destinazione di condivisione, esegui queste operazioni:

1️⃣ Aggiungere un'estensione di destinazione di condivisione

2️⃣ Eseguire l'override del gestore eventi OnShareTargetActivated

3️⃣ Aggiungere le estensioni desktop al progetto UWP

4️⃣ Aggiungere l'estensione del processo di attendibilità totale

5️⃣ Modificare l'applicazione desktop per ottenere il file condiviso

Passaggi seguenti

Aggiungere un'estensione di destinazione di condivisione

In Esplora soluzioni apri il file package.appxmanifest del progetto di creazione pacchetti nella soluzione e aggiungi l'estensione di destinazione di condivisione.

<Extensions>
      <uap:Extension
          Category="windows.shareTarget"
          Executable="ShareTarget.exe"
          EntryPoint="App">
        <uap:ShareTarget>
          <uap:SupportedFileTypes>
            <uap:SupportsAnyFileType />
          </uap:SupportedFileTypes>
          <uap:DataFormat>Bitmap</uap:DataFormat>
        </uap:ShareTarget>
      </uap:Extension>
</Extensions>  

Specifica il nome del file eseguibile generato dal progetto UWP e il nome della classe del punto di ingresso. Questo markup presuppone che il nome del file eseguibile per l'app UWP sia ShareTarget.exe.

Dovrai anche specificare quali tipi di file possono essere condivisi con la tua app. In questo esempio stiamo rendendo l'applicazione desktop WPF PhotoStoreDemo una destinazione di condivisione per le immagini bitmap, quindi specifichiamo Bitmap per il tipo di file supportato.

Eseguire l'override del gestore eventi OnShareTargetActivated

Esegui l'override del gestore eventi OnShareTargetActivated nella classe App del progetto UWP.

Questo gestore eventi viene chiamato quando gli utenti scelgono la tua app per condividere i file.


protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
    shareWithDesktopApplication(args.ShareOperation);
}

private async void shareWithDesktopApplication(ShareOperation shareOperation)
{
    if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
    {
        var items = await shareOperation.Data.GetStorageItemsAsync();
        StorageFile file = items[0] as StorageFile;
        IRandomAccessStreamWithContentType stream = await file.OpenReadAsync();

        await file.CopyAsync(ApplicationData.Current.LocalFolder);
            shareOperation.ReportCompleted();

        await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
    }
}

In questo codice abbiamo salvato l'immagine che viene condivisa dall'utente in una cartella di archiviazione locale delle app. Successivamente, l'applicazione desktop verrà modificata per eseguire il pull delle immagini dalla stessa cartella. L'applicazione desktop può eseguire questa operazione perché è inclusa nello stesso pacchetto dell'app UWP.

Aggiungere le estensioni desktop al progetto UWP

Aggiungere l'estensione Windows Desktop Extensions for the UWP al progetto di app UWP. Si vedrà più di una versione dell'estensione (ad esempio, 10.0.18362.0 e 10.0.19041.0). Per informazioni su come scegliere una versione, vedere SDK estensione e come farvi riferimento.

desktop extension

Aggiungere l'estensione del processo di attendibilità totale

In Esplora soluzioni apri il file package.appxmanifest del progetto di creazione pacchetti nella soluzione e quindi aggiungi l'estensione del processo di attendibilità totale accanto all'estensione di condivisione della destinazione aggiunta in precedenza a questo file.

<Extensions>
  ...
      <desktop:Extension Category="windows.fullTrustProcess" Executable="PhotoStoreDemo\PhotoStoreDemo.exe" />
  ...
</Extensions>  

Questa estensione consentirà all'app UWP di avviare l'applicazione desktop con cui vuoi condividere un file. Nell'esempio facciamo riferimento al file eseguibile dell'applicazione desktop WPF PhotoStoreDemo.

Modificare l'applicazione desktop per ottenere il file condiviso

Modifica l'applicazione desktop per trovare ed elaborare il file condiviso. In questo esempio l'app UWP ha archiviato il file condiviso nella cartella dei dati locali dell'app. Pertanto, modificheremo l'applicazione desktop WPF PhotoStoreDemo per eseguire il pull delle foto da tale cartella.

Photos.Path = Windows.Storage.ApplicationData.Current.LocalFolder.Path;

Per le istanze dell'applicazione desktop già aperte dall'utente, è anche possibile gestire l'evento FileSystemWatcher e passare il percorso in cui si trova il file. In questo modo, tutte le istanze aperte dell'applicazione desktop visualizzeranno la foto condivisa.

...

   FileSystemWatcher watcher = new FileSystemWatcher(Photos.Path);

...

private void Watcher_Created(object sender, FileSystemEventArgs e)
{
    // new file got created, adding it to the list
    Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
    {
        if (File.Exists(e.FullPath))
        {
            ImageFile item = new ImageFile(e.FullPath);
            Photos.Insert(0, item);
            PhotoListBox.SelectedIndex = 0;
            CurrentPhoto.Source = (BitmapSource)item.Image;
        }
    }));
}

Creare un'attività in background

Aggiungi un'attività in background per eseguire il codice anche quando l'app viene sospesa. Le attività in background sono ideali per le piccole attività che non richiedono l'interazione dell'utente. Ad esempio, l'attività può scaricare la posta, visualizzare una notifica di tipo avviso popup su un messaggio di chat in ingresso o rispondere a una modifica in una condizione di sistema.

Ecco un'applicazione di esempio WPF che registra un'attività in background.

background task

L'attività crea una richiesta http e misura il tempo che la richiesta impiega per restituire una risposta. Le tue attività saranno probabilmente più interessanti, ma questo esempio è ideale per imparare il funzionamento di base di un'attività in background.

Vedi l'esempio completo qui.

Pattern di progettazione

Per creare un servizio in background, esegui queste operazioni:

1️⃣ Implementare l'attività in background

2️⃣ Configurare l'attività in background

3️⃣ Registrare l'attività in background

Implementare l'attività in background

Implementa l'attività in background mediante l'aggiunta di codice a un progetto di componente Windows Runtime.

public sealed class SiteVerifier : IBackgroundTask
{
    public async void Run(IBackgroundTaskInstance taskInstance)
    {

        taskInstance.Canceled += TaskInstance_Canceled;
        BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
        var msg = await MeasureRequestTime();
        ShowToast(msg);
        deferral.Complete();
    }

    private async Task<string> MeasureRequestTime()
    {
        string msg;
        try
        {
            var url = ApplicationData.Current.LocalSettings.Values["UrlToVerify"] as string;
            var http = new HttpClient();
            Stopwatch clock = Stopwatch.StartNew();
            var response = await http.GetAsync(new Uri(url));
            response.EnsureSuccessStatusCode();
            var elapsed = clock.ElapsedMilliseconds;
            clock.Stop();
            msg = $"{url} took {elapsed.ToString()} ms";
        }
        catch (Exception ex)
        {
            msg = ex.Message;
        }
        return msg;
    }

Configurare l'attività in background

In Progettazione manifesto apri il file package.appxmanifest del progetto di creazione pacchetti nella soluzione.

Nella scheda Dichiarazioni aggiungi una dichiarazione Attività in background.

Background task option

Quindi, scegli le proprietà desiderate. Il nostro esempio usa la proprietà Timer.

Timer property

Specifica il nome completo della classe nel componente Windows Runtime che implementa l'attività in background.

Specify entry point

Registrare l'attività in background

Aggiungi il codice al progetto di applicazione desktop che registra l'attività in background.

public void RegisterBackgroundTask(String triggerName)
{
    var current = BackgroundTaskRegistration.AllTasks
        .Where(b => b.Value.Name == triggerName).FirstOrDefault().Value;

    if (current is null)
    {
        BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
        builder.Name = triggerName;
        builder.SetTrigger(new MaintenanceTrigger(15, false));
        builder.TaskEntryPoint = "HttpPing.SiteVerifier";
        builder.Register();
        System.Diagnostics.Debug.WriteLine("BGTask registered:" + triggerName);
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("Task already:" + triggerName);
    }
}

Trova le risposte alle tue domande

Altre domande? Partecipa a Stack Overflow. Il nostro team controlla costantemente questi tag. Puoi inviarci le tue domande anche qui.