Search code examples
c#.netwindows-8windowscharms-bar

Windows 8 App start after Share


I am looking for a possibility to start my own Windows App after some content is shared with it through the charm bar. I have found this MS example https://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782/ But after the share button is clicked the app closes. I have tryed it this code at the button click method:

var rootFrame = new Frame();
rootFrame.Navigate(typeof(DefaultPage));
Window.Current.Content = rootFrame;
Window.Current.Activate();

But this has no effect. Also I have tryed to use Application.Start() but the parameter should be a Callback and I don't understand which one.

-------Edit: I want the following behavior.

  1. open IE (already done)
  2. open Charm Bar and click on Share (already done)
  3. select my App (already done)
  4. My App show a Sharing page with information and a share button (already done)
  5. after the share button at my app is clicked open Mainpage (at the MS example the Default page)

So I can't find a solution for the last step. Switching from the Sharing page of my app to the Main Page of my app.

Edit End-------

Every thing I want is to start my App after some content is shared with it. I hope somebody can help me. Or is this not possible?

----Edit 2:

App.xaml.cs:

using System;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

    // The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227

    namespace AppName
    {
        /// <summary>
        /// Provides application-specific behavior to supplement the default Application class.
        /// </summary>
        sealed partial class App : Application
        {
            /// <summary>
            /// Initializes the singleton application object.  This is the first line of authored code
            /// executed, and as such is the logical equivalent of main() or WinMain().
            /// </summary>
            public App()
            {
                this.InitializeComponent();
                this.Suspending += OnSuspending;
            }

            /// <summary>
            /// Invoked when the application is launched normally by the end user.  Other entry points
            /// will be used such as when the application is launched to open a specific file.
            /// </summary>
            /// <param name="e">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {

#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();
                // Set the default language
                rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Save application state and stop any background activity
            deferral.Complete();
        }

        /// <summary>
        /// Invoked when the application is activated as the target of a sharing operation.
        /// </summary>
        /// <param name="e">Details about the activation request.</param>
        protected override void OnShareTargetActivated(Windows.ApplicationModel.Activation.ShareTargetActivatedEventArgs e)
        {
            var shareTargetPage = new AppName.ShareTargetPage();
            shareTargetPage.Activate(e);
            Window.Current.Activate();
        }

        protected override void OnActivated(IActivatedEventArgs args)
        {
            base.OnActivated(args);
        }

    }
}

Mainpage.xaml.cs:

using System;
using Windows.UI.Xaml.Controls;


// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace AppName
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        public void ReceiveUri(Uri sharedWebLink)
        {
            tbMessages.Text = sharedWebLink.ToString();
        }

        protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
        {
            // It is possible to get in this method after the Share button at the 
            // sharetargetpage is clicked but at this point I don't know how to 
            // activate the app

            //base.OnNavigatedTo(e);
        }

    }
}

Sharepargetpage.xaml.cs:

using Windows.UI.Core;
using AppName.Common;
using System;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;

// The Share Target Contract item template is documented at http://go.microsoft.com/fwlink/?LinkId=234241

namespace AppName
{
    /// <summary>
    /// This page allows other applications to share content through this application.
    /// </summary>
    public sealed partial class ShareTargetPage : Page
    {
        private Uri sharedWebLink;


        /// <summary>
        /// Provides a channel to communicate with Windows about the sharing operation.
        /// </summary>
        private Windows.ApplicationModel.DataTransfer.ShareTarget.ShareOperation _shareOperation;
        private ObservableDictionary defaultViewModel = new ObservableDictionary();

        /// <summary>
        /// This can be changed to a strongly typed view model.
        /// </summary>
        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }

        public ShareTargetPage()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Invoked when another application wants to share content through this application.
        /// </summary>
        /// <param name="e">Activation data used to coordinate the process with Windows.</param>
        public async void Activate(ShareTargetActivatedEventArgs e)
        {
            this._shareOperation = e.ShareOperation;

            // Communicate metadata about the shared content through the view model
            var shareProperties = this._shareOperation.Data.Properties;
            var thumbnailImage = new BitmapImage();
            this.DefaultViewModel["Title"] = shareProperties.Title;
            this.DefaultViewModel["Description"] = shareProperties.Description;
            this.DefaultViewModel["Image"] = thumbnailImage;
            this.DefaultViewModel["Sharing"] = false;
            this.DefaultViewModel["ShowImage"] = false;
            this.DefaultViewModel["Comment"] = String.Empty;
            this.DefaultViewModel["Placeholder"] = "Add a comment";
            this.DefaultViewModel["SupportsComment"] = true;
            Window.Current.Content = this;
            Window.Current.Activate();

            try
            {
                this.sharedWebLink = await this._shareOperation.Data.GetWebLinkAsync();
                this.DefaultViewModel["URL"] = this.sharedWebLink.ToString();
            }
            catch (Exception ex)
            {
                NotifyUserBackgroundThread("Failed GetWebLinkAsync - " + ex.Message, NotifyType.ErrorMessage);
            }

            // Update the shared content's thumbnail image in the background
            if (shareProperties.Thumbnail != null)
            {
                var stream = await shareProperties.Thumbnail.OpenReadAsync();
                thumbnailImage.SetSource(stream);
                this.DefaultViewModel["ShowImage"] = true;
            }
        }

        /// <summary>
        /// Invoked when the user clicks the Share button.
        /// </summary>
        /// <param name="sender">Instance of Button used to initiate sharing.</param>
        /// <param name="e">Event data describing how the button was clicked.</param>
        private void ShareButton_Click(object sender, RoutedEventArgs e)
        {
            this.DefaultViewModel["Sharing"] = true;
            this._shareOperation.ReportStarted();

            // TODO: Perform work appropriate to your sharing scenario using
            //       this._shareOperation.Data, typically with additional information captured
            //       through custom user interface elements added to this page such as 
            //       this.DefaultViewModel["Comment"]

            this._shareOperation.ReportCompleted();

            // TRY1: Navigate to MainPage
            //Frame rootFrame = Window.Current.Content as Frame;
            //if(rootFrame == null)
            //{
            //    rootFrame = new Frame();
            //    Window.Current.Content = rootFrame;
            //}
            //if(rootFrame.Content == null)
            //{
            //    rootFrame.Navigate(typeof(MainPage));
            //}

            //  TRY2: Navigate to MainPage
            //var p = rootFrame.Content as MainPage;
            //p.ReceiveUri(sharedWebLink);
            //Window.Current.Activate();


            var rootFrame = new Frame();
            rootFrame.Navigate(typeof(MainPage));
            Window.Current.Content = rootFrame;
            Window.Current.Activate();

            // TRY3: Start the App
            // Application.Start();
            // App.Start();
            // but I don't know which callback method should be the param of start
        }

        async private void NotifyUserBackgroundThread(string message, NotifyType type)
        {
            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                NotifyUser(message, type);
            });
        }

        private void NotifyUser(string strMessage, NotifyType type)
        {
            switch (type)
            {
                // Use the status message style.
                case NotifyType.StatusMessage:
                    StatusBlock.Style = Resources["StatusStyle"] as Style;
                    break;
                // Use the error message style.
                case NotifyType.ErrorMessage:
                    StatusBlock.Style = Resources["ErrorStyle"] as Style;
                    break;
            }
            StatusBlock.Text = strMessage;
        }

        public enum NotifyType
        {
            StatusMessage,
            ErrorMessage
        };
    }
}

Edit 2 End ---------


Solution

  • To enable your app's behavior as Share Targeted app, you have to override OnShareTargetActivated(ShareTargetActivatedEventArgs args) method in App class.

    protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
    {
        var rootFrame = new Frame();
    
        // TODO: Load content in frame
    
        Window.Current.Content = rootFrame;
        Window.Current.Activate();
    }
    

    EDIT

    From your current implementation you are going to setShareTargetPage inside windows and later you cast Windows.Current.Content to Frame that is always null. So, you can't do this way. My recommendation is to do it this way.

    Change OnShareTargetActivated method inside App.xaml.cs to this

    protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
    {
        var rootFrame = new Frame();
        rootFrame.Navigate(typeof(ShareTargetPage), args);
        Window.Current.Content = rootFrame;
        Window.Current.Activate();
    }
    

    Remove this from Activate method in ShareTargetPage.xaml.cs

    Window.Current.Content = this;
    Window.Current.Activate();
    

    Overrides OnNavigatedTo in ShareTargetPage class

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        // Calling Activate method here
        Activate((ShareTargetActivatedEventArgs)e.Parameter);
    }
    

    And then to navigate to another page you can simply Calls Frame.Navigation something like that inside ShareTargetPage

    this.Frame.Navigate(typeof(MainPage));
    

    EDIT 2

    If you want to navigate to another page on share button click then remove this line of code

    this._shareOperation.ReportCompleted();
    

    This calling above method informs the OS that your app has finished sharing request and is now safely terminated. That's why your app terminates without navigation to another page