• 讲讲我在Windows10(uwp)开发中遇到的一些坑.


    7月29日发布的Windows10正式版,当天安装好以后,在网络不太好的情况下,经过多次尝试终于装上了Visual Studio 2015和Windows 10 10240的SDK.这两周一直在开发UWP,讲讲在其中遇到的一些坑,不定时更新,有兴趣的可以关注下.

    1.DataType在UWP中缺失的问题

    在WPF中使用过MVVMLight的都知道,我们可以在App.xaml文件中通过DataType将ViewModel和View绑定在一起.

    1 <DataTemplate DataType="{x:Type vm:MyViewModel}">
    2     <views:MyView/>
    3 </DataTemplate>

    但是在Windows10(包括WP7等),是没有DataType的属性的,这意味着我们不能用这种方式来实现ViewModel和View的绑定.但是我们可以曲线救国一下,通过key的方式来寻找DataTemplate来绑定.

    首先,我们需要改变我们在UWP中的写法.

    1 <DataTemplate x:Key="MyViewModel">
    2     <view:MyView/>
    3 </DataTemplate>

    然后我们在我们的MainPage.xaml文件中加入一个ContentControl.

    1 <ContentControl Content="{Binding CurrentViewModel}" ContentTemplate="{Binding Path=CurrentTemplate}" />

    我们的各个Views是用Usercontrol实现的.我们需要在MainPageViewModel中添加相应的绑定项.

     1 public ViewModelBase CurrentViewModel
     2 {
     3     get
     4     {
     5         return currentViewModel;
     6     }
     7     set
     8     {
     9         if (currentViewModel == value)
    10         {
    11             return;
    12 
    13         }
    14         currentViewModel = value;
    15         RaisePropertyChanged(()=>CurrentViewModel);
    16         RaisePropertyChanged(()=>CurrentTemplate);
    17     }
    18 }
    19 
    20 public DataTemplate CurrentTemplate
    21 {
    22     get
    23     {
    24         if (CurrentViewModel == null)
    25         {
    26             return null;
    27         }
    28 
    29         return Untils.DataTemplateSelector.GetTemplate(CurrentViewModel);
    30     }
    31 }

    DataTemplateSelector.GetTemplate是我们整个方法的核心.

    1 public static class DataTemplateSelector
    2 {
    3     public static DataTemplate GetTemplate(ViewModelBase param)
    4     {
    5         Type t = param.GetType();
    6         return App.Current.Resources[t.Name] as DataTemplate;
    7     }
    8 }

    通过查找Key的方式将ViewModel和View绑定在一起,这样就实现了我们的功能.我们接下来只要关注App.xaml或者相关文件中声明我们的Key就行了.

    2.附加属性解决WebView不能直接绑定Html内容的问题

    WebView的Source属性只能绑定微软规定的一些地址协议,不能直接绑定HTML的内容.通过附加属性可以解决这个问题,利用的是NavigateToString方法

     1 public static readonly DependencyProperty SourceStringProperty =
     2 DependencyProperty.RegisterAttached("SourceString", typeof(string), typeof(Untils), new PropertyMetadata("", OnSourceStringChanged));
     3 
     4 public static string GetSourceString(DependencyObject obj) { return obj.GetValue(SourceStringProperty).ToString(); }
     5 public static void SetSourceString(DependencyObject obj, string value) { obj.SetValue(SourceStringProperty, value); }
     6 
     7 private static void OnSourceStringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     8 {
     9     WebView wv = d as WebView;
    10     if (wv != null)
    11     {
    12         wv.NavigateToString(e.NewValue.ToString());
    13     }
    14 }

    声明一个SourceString的附加属性,然后在变更事件中进行导航,然后Xaml文件中:

     1 <WebView Property:Untils.SourceString="{Binding Url,Mode=TwoWay}"/> 

    这样子,就可以直接绑定Html内容了.

    3.异步(async)方法中的异常无法被App的UnhandledException捕获的问题.

    这是一个比较严重的问题.目前已知很多的做法就是局部try catch来解决这个问题.这样做是很容易导致Process被强制终止然后引起闪退的问题的.

    我这里用了一个线程同步模型类解决这个问题.

      1 using System;
      2 using System.Threading;
      3 using Windows.UI.Xaml.Controls;
      4 
      5 namespace AiJianShu.ExceptionHandler
      6 {
      7     internal class ExceptionHandlingSynchronizationContext : SynchronizationContext
      8     {
      9         /// <summary>
     10         /// 注册事件.  需要在OnLaunched和OnActivated事件中调用
     11         /// </summary>
     12         /// <returns></returns>
     13         public static ExceptionHandlingSynchronizationContext Register()
     14         {
     15             var syncContext = Current;
     16             if (syncContext == null)
     17                 throw new InvalidOperationException("Ensure a synchronization context exists before calling this method.");
     18 
     19 
     20             var customSynchronizationContext = syncContext as ExceptionHandlingSynchronizationContext;
     21 
     22 
     23             if (customSynchronizationContext == null)
     24             {
     25                 customSynchronizationContext = new ExceptionHandlingSynchronizationContext(syncContext);
     26                 SetSynchronizationContext(customSynchronizationContext);
     27             }
     28 
     29 
     30             return customSynchronizationContext;
     31         }
     32 
     33         /// <summary>
     34         /// 将线程的上下文绑定到特定的Frame上面
     35         /// </summary>
     36         /// <param name="rootFrame"></param>
     37         /// <returns></returns>
     38         public static ExceptionHandlingSynchronizationContext RegisterForFrame(Frame rootFrame)
     39         {
     40             if (rootFrame == null)
     41                 throw new ArgumentNullException("rootFrame");
     42 
     43             var synchronizationContext = Register();
     44 
     45             rootFrame.Navigating += (sender, args) => EnsureContext(synchronizationContext);
     46             rootFrame.Loaded += (sender, args) => EnsureContext(synchronizationContext);
     47 
     48             return synchronizationContext;
     49         }
     50 
     51         private static void EnsureContext(SynchronizationContext context)
     52         {
     53             if (Current != context)
     54                 SetSynchronizationContext(context);
     55         }
     56 
     57 
     58         private readonly SynchronizationContext _syncContext;
     59 
     60 
     61         public ExceptionHandlingSynchronizationContext(SynchronizationContext syncContext)
     62         {
     63             _syncContext = syncContext;
     64         }
     65 
     66 
     67         public override SynchronizationContext CreateCopy()
     68         {
     69             return new ExceptionHandlingSynchronizationContext(_syncContext.CreateCopy());
     70         }
     71 
     72 
     73         public override void OperationCompleted()
     74         {
     75             _syncContext.OperationCompleted();
     76         }
     77 
     78 
     79         public override void OperationStarted()
     80         {
     81             _syncContext.OperationStarted();
     82         }
     83 
     84 
     85         public override void Post(SendOrPostCallback d, object state)
     86         {
     87             _syncContext.Post(WrapCallback(d), state);
     88         }
     89 
     90 
     91         public override void Send(SendOrPostCallback d, object state)
     92         {
     93             _syncContext.Send(d, state);
     94         }
     95 
     96 
     97         private SendOrPostCallback WrapCallback(SendOrPostCallback sendOrPostCallback)
     98         {
     99             return state =>
    100             {
    101                 try
    102                 {
    103                     sendOrPostCallback(state);
    104                 }
    105                 catch (Exception ex)
    106                 {
    107                     if (!HandleException(ex))
    108                         throw;
    109                 }
    110             };
    111         }
    112 
    113         private bool HandleException(Exception exception)
    114         {
    115             if (UnhandledException == null)
    116                 return false;
    117 
    118             var exWrapper = new AysncUnhandledExceptionEventArgs
    119             {
    120                 Exception = exception
    121             };
    122 
    123             UnhandledException(this, exWrapper);
    124 
    125 #if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
    126             if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
    127 #endif
    128             return exWrapper.Handled;
    129         }
    130 
    131         public event EventHandler<AysncUnhandledExceptionEventArgs> UnhandledException;
    132     }
    133 
    134     public class AysncUnhandledExceptionEventArgs : EventArgs
    135     {
    136         public bool Handled { get; set; }
    137         public Exception Exception { get; set; }
    138     }
    139 }

    使用实例:

     1 public App()
     2 {
     3     this.InitializeComponent();
     4     this.Suspending += OnSuspending;
     5 
     6     this.UnhandledException += App_UnhandledException;
     7 
     8 }
     9 
    10 private void RegisterExceptionHandlingSynchronizationContext()
    11 {
    12     ExceptionHandlingSynchronizationContext
    13         .Register()
    14         .UnhandledException += SynchronizationContext_UnhandledException;
    15 }
    16 
    17 private async void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
    18 {
    19     e.Handled = true;
    20 
    21     await new MessageDialog("Application Unhandled Exception:
    " + e.Exception.Message)
    22         .ShowAsync();
    23 }
    24 
    25 private async void SynchronizationContext_UnhandledException(object sender, AysncUnhandledExceptionEventArgs e)
    26 {
    27     e.Handled = true;
    28 
    29     await new MessageDialog("Synchronization Context Unhandled Exception:
    " + e.Exception.Message)
    30         .ShowAsync();
    31 }
    32 
    33 protected override void OnLaunched(LaunchActivatedEventArgs e)
    34 {
    35     RegisterExceptionHandlingSynchronizationContext();
    36 
    37 #if DEBUG
    38     if (System.Diagnostics.Debugger.IsAttached)
    39     {
    40         this.DebugSettings.EnableFrameRateCounter = true;
    41     }
    42 #endif
    43 
    44     Frame rootFrame = Window.Current.Content as Frame;
    45 
    46     // 不要在窗口已包含内容时重复应用程序初始化,
    47     // 只需确保窗口处于活动状态
    48     if (rootFrame == null)
    49     {
    50         // 创建要充当导航上下文的框架,并导航到第一页
    51         rootFrame = new Frame();
    52 
    53         rootFrame.NavigationFailed += OnNavigationFailed;
    54 
    55         if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
    56         {
    57             //TODO: 从之前挂起的应用程序加载状态
    58         }
    59 
    60         // 将框架放在当前窗口中
    61         Window.Current.Content = rootFrame;
    62     }
    63 
    64     if (rootFrame.Content == null)
    65     {
    66         // 当导航堆栈尚未还原时,导航到第一页,
    67         // 并通过将所需信息作为导航参数传入来配置
    68         // 参数
    69         rootFrame.Navigate(typeof(MainPage), e.Arguments);
    70     }
    71     // 确保当前窗口处于活动状态
    72     Window.Current.Activate();
    73 }
    74 
    75 protected override void OnActivated(IActivatedEventArgs args)
    76 {
    77     RegisterExceptionHandlingSynchronizationContext();
    78     base.OnActivated(args);
    79 }

    这样全局的异常就都能在App.xaml.cs文件中被捕获,不会导致闪退.

    参考资料:

    http://www.codeproject.com/Articles/113152/Applying-Data-Templates-Dynamically-by-Type-in-WP

    http://www.markermetro.com/2013/01/technical/handling-unhandled-exceptions-with-asyncawait-on-windows-8-and-windows-phone-8/

    https://github.com/kiwidev/WinRTExceptions

  • 相关阅读:
    Java不带.classpath的svn项目下载,转成到eclipse中
    eclipse 实用快捷键(最全)
    加密算法IV的作用
    Hadoop环境常用命令
    Centos网络配置
    apache指定的网络名不再可用
    Toritoisegit记住用户名密码
    用JavaScript修改CSS属性的代码
    div 旋转
    过滤器、监听器、拦截器的区别
  • 原文地址:https://www.cnblogs.com/youngytj/p/4749004.html
Copyright © 2020-2023  润新知