uwp磁贴与分享

制作磁贴

  • 要求使用标准的处理XML DOM方式创建动态磁贴
  • 要求采用Adaptive Tile (覆盖至少small、medium、wide)
  • 实现效果:要求每添加一条项目,磁贴能进行更新,并且更新的内容循环展示(1-2-3-4-5-1-2-3-4……)
  • (Bonus:为磁贴添加背景图片)

设置磁贴

双击项目列表中的Package.appxmanifest文件,然后将想要显示的图片放到相应的图标里面就可以,像素一定要吻合,我是直接从百度图片上,按照像素大小筛选图片,随便选的,就不用格外的图片处理。
磁贴的设置

磁贴的更新

在MainPage.xaml.cs中加入下面函数

private void UpdatePrimaryTile(string input,string input2)
        {
            var xmlDoc = TileService.CreateTiles(new PrimaryTile(input,input2));

            var updater = TileUpdateManager.CreateTileUpdaterForApplication();
            TileNotification notification = new TileNotification(xmlDoc);
            updater.Update(notification);
        }

里面有TileService.CreateTiles这个函数,主要用来创建一个xml文件,然后将文件放到TileNotification文件里update就可以实现磁贴的更新了。

TileService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
using first_project.Models;
using System.Xml.Linq;


namespace first_project.Services
{
    class TileService
    {
        public static Windows.Data.Xml.Dom.XmlDocument CreateTiles(PrimaryTile primaryTile)
        {
            XDocument xDoc = new XDocument(
                new XElement("tile", new XAttribute("version", 3),
                    new XElement("visual",
                        // Small Tile
                        new XElement("binding", new XAttribute("branding", primaryTile.branding), new XAttribute("displayName", primaryTile.appName), new XAttribute("template", "TileSmall"),
                        new XElement("image", new XAttribute("placement", "background"), new XAttribute("src", "Assets/1.scale-200.png")),
                        new XElement("group",
                                new XElement("subgroup",
                                    new XElement("text", primaryTile.time, new XAttribute("hint-style", "caption")),
                                    new XElement("text", primaryTile.message, new XAttribute("hint-style", "captionsubtle"), new XAttribute("hint-wrap", true), new XAttribute("hint-maxLines", 3))
                                )
                            )
                        ),
                        // Wide Tile
                        new XElement("binding", new XAttribute("branding", primaryTile.branding), new XAttribute("displayName", primaryTile.appName), new XAttribute("template", "TileWide"),
                        new XElement("image", new XAttribute("placement", "background"), new XAttribute("src", "Assets/3.png")),
                        new XElement("group",
                                new XElement("subgroup",
                                    new XElement("text", primaryTile.time, new XAttribute("hint-style", "caption")),
                                    new XElement("text", primaryTile.message, new XAttribute("hint-style", "captionsubtle"), new XAttribute("hint-wrap", true), new XAttribute("hint-maxLines", 3))
                                    ),
                                new XElement("subgroup", new XAttribute("hint-weight", 15),
                                    new XElement("image", new XAttribute("placement", "inline"), new XAttribute("src", "Assets/StoreLogo.png"))
                                )
                            )
                        ),

                        // Medium Tile
                        new XElement("binding", new XAttribute("branding", primaryTile.branding), new XAttribute("displayName", primaryTile.appName), new XAttribute("template", "TileMedium"),
                            new XElement("image", new XAttribute("placement", "background"), new XAttribute("src", "Assets/2.png")),
                            new XElement("group",
                                new XElement("subgroup",
                                    new XElement("text", primaryTile.time, new XAttribute("hint-style", "caption")),
                                    new XElement("text", primaryTile.message, new XAttribute("hint-style", "captionsubtle"), new XAttribute("hint-wrap", true), new XAttribute("hint-maxLines", 3))
                                )
                            )
                        )
                    )
                )
            );

            Windows.Data.Xml.Dom.XmlDocument xmlDoc = new Windows.Data.Xml.Dom.XmlDocument();
            xmlDoc.LoadXml(xDoc.ToString());
            return xmlDoc;
        }



    }
}

这个就是上文提到的TileService.cs类,用的是c#的方式创建xml,当然可以直接写xml,有关这个文件基本上是不会报错的,就是说即使不小心写错了,也只能肉眼debug,所以这个文件我几乎没改,因为我之前绑定的不是PrimaryTile类,而是ListItem类,这样就可以将ListItem的数据显示在磁贴上,但是无论怎么做都没有反应,我估计可能还是xml文件的问题,于是我尽量不修改官方文档中的xml文件。

PrimaryTile .cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace first_project.Models
{
    public class PrimaryTile
    {
        public string time { get; set; } = "ok";
        public string message { get; set; } = "nothing";
        public string message2 { get; set; } = " At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident.";
        public string branding { get; set; } = "name";
        public string appName { get; set; } = "HoL";

        public PrimaryTile(string input,string input2) {
            time = input;
            message = input2;
        }
    }

}

这个就是不得已写的PrimaryTile 类,其中的input和input2,我传入的是ListItem中的title和description,所以也算实现绑定了。

磁贴的循环

首先在App.xaml.cs的构造函数中加入下面两句,第一句清空,第二句建立循环队列。

TileUpdateManager.CreateTileUpdaterForApplication().Clear();
TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);

在MainPage.xaml.cs中加入下面函数

扫描二维码关注公众号,回复: 1760377 查看本文章
private void circulationUpdate()
        {
            TileUpdateManager.CreateTileUpdaterForApplication().Clear();
            for (int i = 0;i< ((App)App.Current).ViewModel.AllItems.Count(); i++)
            {
                UpdatePrimaryTile(((App)App.Current).ViewModel.AllItems[i].title, ((App)App.Current).ViewModel.AllItems[i].description);
            }
        }

函数作用是,一开始清空,然后将所有的ListItem的title和description用UpdatePrimaryTile生成xml文件,这样的话就可以实现循环显示,这个循环队列应该是有上限的,但是没测试过,至少五个是没问题的,可以满足要求。

Bouns,磁贴设置背景图片

就一句话new XElement("image", new XAttribute("placement", "background"), new XAttribute("src", "Assets/1.scale-200.png")),上面的TileService.cs类中已经有了,我是每个背景图片就是原本的磁贴样式。

实现App-to-App communication

  • 在MenuFlyoutItem中增加Share选项,点击后相应条目能以邮件方式进行共享(不要求动态共享图片)
  • 动态共享图片(虽然没要求)

在MainPage.xmal中,将下面代码放到ListItem内容中的后面,那么每一行就会多出一个设置按钮,点击之后会出现share文字。

<AppBarButton Grid.Column="3" Icon="Setting" IsCompact="True">
      <AppBarButton.Flyout>
             <MenuFlyout>
                  <MenuFlyoutItem Text="Share" Click="MenuFlyoutItem_Click"/>
             </MenuFlyout>
      </AppBarButton.Flyout>
</AppBarButton> 

以邮件方式共享

在MainPage.xaml.cs中

两个函数中的结尾分别加一句话

protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
        ......
            DataTransferManager.GetForCurrentView().DataRequested -= OnShareDataRequested;
        }
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    ......
    DataTransferManager.GetForCurrentView().DataRequested += OnShareDataRequested;
}

MenuFlyoutItem_Click

当点击share的时候调用这个函数,selectedItem就是点击share所在的那个ListItem,我把它设置为MainPage.xaml.cs文件的全局变量。

private void MenuFlyoutItem_Click(object sender, RoutedEventArgs e)
        {
            MenuFlyoutItem se = sender as MenuFlyoutItem;
            var dc = se.DataContext as ListItem;
            selectedItem = dc;
            DataTransferManager.ShowShareUI();
        }

OnShareDataRequested

这个函数就是传送的包,为包赋值,如果不加入图片的话就这样可以了。

public void OnShareDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            var dp = args.Request.Data;
            var deferral = args.Request.GetDeferral();
            dp.Properties.Title = selectedItem.title;
            dp.Properties.Description = selectedItem.description;
            dp.SetWebLink(new Uri("http://seattletimes.com/ABPub/2006/01/10/2002732410.jpg"));
            deferral.Complete();
        }

动态共享图片

这个实现起来还是有点难度的,下面是PPT里面的方法,这个方法似乎连创建静态的图片都成问题,至少我没成功。

async void OnShareDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{    
    var dp = args.Request.Data;    
    var deferral = args.Request.GetDeferral();    
    var photoFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/needle.jpg"));    
    dp.Properties.Title = "Space Needle";    
    dp.Properties.Description = "The Space Needle in Seattle, WA";    
    dp.SetStorageItems(new List<StorageFile> { photoFile });    
    dp.SetWebLink(new Uri("http://seattletimes.com/ABPub/2006/01/10/2002732410.jpg"));    
    deferral.Complete();
}

我的方法

在MainPage.xaml.cs中加入一个全局变量public StorageFile imageFile;,然后在Select_ClickStorageFile file = await openPicker.PickSingleFileAsync();如果file != null,则imageFile = file;这样在选择的时候就会得到imageFile文件。

OnShareDataRequested

public void OnShareDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            var dp = args.Request.Data;
            var deferral = args.Request.GetDeferral();
            dp.Properties.Title = selectedItem.title;
            dp.Properties.Description = selectedItem.description;
            try
            {
                dp.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageFile));
            }
            catch
            {
                dp.SetBitmap(RandomAccessStreamReference.CreateFromUri(selectedItem.src.UriSource));
            }
            dp.SetWebLink(new Uri("http://seattletimes.com/ABPub/2006/01/10/2002732410.jpg"));
            deferral.Complete();
        }

因为有两种可能,一种直接分享,没有点击选择图片按钮,那么imageFile是空,就会异常,所以直接用选择的selectedItem.src.UriSource,为什么不直接用selectedItem.src.UriSource呢,这就是奇怪的地方,只有不选的时候这个值才不是空,一旦选择图片了,这个值就是空值,无论是传到NewPage,还是点击的时候查看,放在监视器里面看都是空值,所以当选择了之后换一种写法,将CreateFromUri换成CreateFromFile,然后传入imageFile。

图片的bug

最后发现有一点小bug,在我第一次选择了图片之后,重启项目发现,不是默认的图片,而是选择了的图片,这个时候如果再选择图片,则try和catch中的值都为空,所以就会报错。
经过排查是上次的项目有问题,当页面是新打开的时候,没有清空FutureAccessList里面的图片,导致会遗留到下一次打开,以下是新的OnNavigatedTo函数,在MainPage.xaml.cs中。

protected override async void OnNavigatedTo(NavigationEventArgs e)
        {

            if (e.NavigationMode == NavigationMode.New)
            {
                ApplicationData.Current.LocalSettings.Values.Remove("MainPage");
                ApplicationData.Current.LocalSettings.Values["TempImage"] = null;
            }

            if (ApplicationData.Current.LocalSettings.Values["TempImage"] != null)
            {
                StorageFile tempimg;
                tempimg = await StorageApplicationPermissions.FutureAccessList.GetFileAsync((string)ApplicationData.Current.LocalSettings.Values["TempImage"]);
                IRandomAccessStream ir = await tempimg.OpenAsync(FileAccessMode.Read);
                BitmapImage bi = new BitmapImage();
                await bi.SetSourceAsync(ir);
                NewImage.Source = bi;
                ApplicationData.Current.LocalSettings.Values["TempImage"] = null;
            }


            {
                if (ApplicationData.Current.LocalSettings.Values.ContainsKey("MainPage"))
                {
                    var composite = ApplicationData.Current.LocalSettings.Values["MainPage"] as ApplicationDataCompositeValue;
                    TitleBlock.Text = (string)composite["Title"];
                    DetailBlock.Text = (string)composite["Details"];
                    Date.Date = (DateTimeOffset)composite["Date"];
                    ((App)App.Current).ViewModel.AllItems[0].Completed = (bool)composite["Visible"];
                    ApplicationData.Current.LocalSettings.Values.Remove("MainPage");
                }
            }

            DataTransferManager.GetForCurrentView().DataRequested += OnShareDataRequested;
        }

视频和资源

视频和资源

猜你喜欢

转载自blog.csdn.net/yaoxh6/article/details/79888689
UWP