1. 程式人生 > >講講我在Windows10(uwp)開發中遇到的一些坑

講講我在Windows10(uwp)開發中遇到的一些坑

7月29日釋出的Windows10正式版,當天安裝好以後,在網路不太好的情況下,經過多次嘗試終於裝上了Visual Studio 2015和Windows 10 10240的SDK.這兩週一直在開發UWP,講講在其中遇到的一些坑,不定時更新,有興趣的可以關注下.

1.DataType在UWP中缺失的問題

在WPF中使用過MVVMLight的都知道,我們可以在App.xaml檔案中通過DataType將ViewModel和View繫結在一起.

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

但是在Windows10(包括WP7等),是沒有DataType的屬性的,這意味著我們不能用這種方式來實現ViewModel和View的繫結.但是我們可以曲線救國一下,通過key的方式來尋找DataTemplate來繫結.

首先,我們需要改變我們在UWP中的寫法.

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



然後我們在我們的MainPage.xaml檔案中加入一個ContentControl.

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


我們的各個Views是用Usercontrol實現的.我們需要在MainPageViewModel中新增相應的繫結項.

public ViewModelBase CurrentViewModel
{
     get
    {
         return currentViewModel;
    }
     set
    {
        if (currentViewModel == value)
        {
             return;

        }
         currentViewModel = value;
        RaisePropertyChanged(()=>CurrentViewModel);
         RaisePropertyChanged(()=>CurrentTemplate);
     }
 }
 
public DataTemplate CurrentTemplate
 {
     get
    {
         if (CurrentViewModel == null)
         {
             return null;
         }
 
         return Untils.DataTemplateSelector.GetTemplate(CurrentViewModel);
     }
 }




DataTemplateSelector.GetTemplate是我們整個方法的核心.

public static class DataTemplateSelector
{
    public static DataTemplate GetTemplate(ViewModelBase param)
     {
         Type t = param.GetType();
         return App.Current.Resources[t.Name] as DataTemplate;
     }
 }

通過查詢Key的方式將ViewModel和View繫結在一起,這樣就實現了我們的功能.我們接下來只要關注App.xaml或者相關檔案中宣告我們的Key就行了.

2.附加屬性解決WebView不能直接繫結Html內容的問題

WebView的Source屬性只能繫結微軟規定的一些地址協議,不能直接繫結HTML的內容.通過附加屬性可以解決這個問題,利用的是NavigateToString方法


public static readonly DependencyProperty SourceStringProperty =
DependencyProperty.RegisterAttached("SourceString", typeof(string), typeof(Untils), new PropertyMetadata("", OnSourceStringChanged));

 public static string GetSourceString(DependencyObject obj) { return obj.GetValue(SourceStringProperty).ToString(); }
public static void SetSourceString(DependencyObject obj, string value) { obj.SetValue(SourceStringProperty, value); }
 
 private static void OnSourceStringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
 {
     WebView wv = d as WebView;
    if (wv != null)
     {
        wv.NavigateToString(e.NewValue.ToString());
     }
 }

宣告一個SourceString的附加屬性,然後在變更事件中進行導航,然後Xaml檔案中:
 <WebView Property:Untils.SourceString="{Binding Url,Mode=TwoWay}"/> 

這樣子,就可以直接繫結Html內容了.

3.非同步(async)方法中的異常無法被App的UnhandledException捕獲的問題.

這是一個比較嚴重的問題.目前已知很多的做法就是區域性try catch來解決這個問題.這樣做是很容易導致Process被強制終止然後引起閃退的問題的.

我這裡用了一個執行緒同步模型類解決這個問題.

 using System;
 using System.Threading;
 using Windows.UI.Xaml.Controls;
 
 namespace AiJianShu.ExceptionHandler
  {
     internal class ExceptionHandlingSynchronizationContext : SynchronizationContext
     {
        /// <summary>
        /// 註冊事件.  需要在OnLaunched和OnActivated事件中呼叫
         /// </summary>
        /// <returns></returns>
        public static ExceptionHandlingSynchronizationContext Register()
        {
             var syncContext = Current;
             if (syncContext == null)
               throw new InvalidOperationException("Ensure a synchronization context exists before calling this method.");
 
 
             var customSynchronizationContext = syncContext as ExceptionHandlingSynchronizationContext;


             if (customSynchronizationContext == null)
             {
                 customSynchronizationContext = new ExceptionHandlingSynchronizationContext(syncContext);
                SetSynchronizationContext(customSynchronizationContext);
             }


            return customSynchronizationContext;
        }

         /// <summary>
          /// 將執行緒的上下文繫結到特定的Frame上面
         /// </summary>
         /// <param name="rootFrame"></param>
         /// <returns></returns>
         public static ExceptionHandlingSynchronizationContext RegisterForFrame(Frame rootFrame)
         {
             if (rootFrame == null)
                 throw new ArgumentNullException("rootFrame");
 
           var synchronizationContext = Register();
 
            rootFrame.Navigating += (sender, args) => EnsureContext(synchronizationContext);
             rootFrame.Loaded += (sender, args) => EnsureContext(synchronizationContext);

            return synchronizationContext;
        }

        private static void EnsureContext(SynchronizationContext context)
         {
            if (Current != context)
                 SetSynchronizationContext(context);
         }
 
 
        private readonly SynchronizationContext _syncContext;
 
 
         public ExceptionHandlingSynchronizationContext(SynchronizationContext syncContext)
         {
             _syncContext = syncContext;
         }
 
 
        public override SynchronizationContext CreateCopy()
         {
             return new ExceptionHandlingSynchronizationContext(_syncContext.CreateCopy());
        }
 
 
         public override void OperationCompleted()
         {
             _syncContext.OperationCompleted();
        }

 
         public override void OperationStarted()
         {
             _syncContext.OperationStarted();
        }

 
         public override void Post(SendOrPostCallback d, object state)
         {
           _syncContext.Post(WrapCallback(d), state);
         }
 
 
         public override void Send(SendOrPostCallback d, object state)
       {
             _syncContext.Send(d, state);
         }
 
 
         private SendOrPostCallback WrapCallback(SendOrPostCallback sendOrPostCallback)
        {
             return state =>
            {
                 try
                {
                     sendOrPostCallback(state);
                }
                catch (Exception ex)
                 {
                     if (!HandleException(ex))
                         throw;
                 }
             };
        }
 
        private bool HandleException(Exception exception)
         {
             if (UnhandledException == null)
                 return false;
 
             var exWrapper = new AysncUnhandledExceptionEventArgs
             {
                 Exception = exception
             };

             UnhandledException(this, exWrapper);
 
 #if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
             if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
 #endif
             return exWrapper.Handled;
         }
 
         public event EventHandler<AysncUnhandledExceptionEventArgs> UnhandledException;
     }
 
     public class AysncUnhandledExceptionEventArgs : EventArgs
     {
         public bool Handled { get; set; }
         public Exception Exception { get; set; }
     }
 }


使用例項:

public App()
 {
     this.InitializeComponent();
     this.Suspending += OnSuspending;
 
     this.UnhandledException += App_UnhandledException;

}
 
 private void RegisterExceptionHandlingSynchronizationContext()
 {
    ExceptionHandlingSynchronizationContext
         .Register()
         .UnhandledException += SynchronizationContext_UnhandledException;
 }
 
 private async void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
 {
     e.Handled = true;
 
     await new MessageDialog("Application Unhandled Exception:\r\n" + e.Exception.Message)
         .ShowAsync();
 }

 private async void SynchronizationContext_UnhandledException(object sender, AysncUnhandledExceptionEventArgs e)
 {
     e.Handled = true;
 
     await new MessageDialog("Synchronization Context Unhandled Exception:\r\n" + e.Exception.Message)
         .ShowAsync();
 }
 
 protected override void OnLaunched(LaunchActivatedEventArgs e)
 {
     RegisterExceptionHandlingSynchronizationContext();

 #if DEBUG
     if (System.Diagnostics.Debugger.IsAttached)
     {
         this.DebugSettings.EnableFrameRateCounter = true;
    }
 #endif
 
    Frame rootFrame = Window.Current.Content as Frame;
 
     // 不要在視窗已包含內容時重複應用程式初始化,
     // 只需確保視窗處於活動狀態
     if (rootFrame == null)
     {
        // 建立要充當導航上下文的框架,並導航到第一頁
        rootFrame = new Frame();

        rootFrame.NavigationFailed += OnNavigationFailed;

        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
         {
             //TODO: 從之前掛起的應用程式載入狀態
        }

         // 將框架放在當前視窗中
        Window.Current.Content = rootFrame;
    }

     if (rootFrame.Content == null)
     {
         // 當導航堆疊尚未還原時,導航到第一頁,
         // 並通過將所需資訊作為導航引數傳入來配置
         // 引數
        rootFrame.Navigate(typeof(MainPage), e.Arguments);
     }
     // 確保當前視窗處於活動狀態
    Window.Current.Activate();
 }

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

這樣全域性的異常就都能在App.xaml.cs檔案中被捕獲,不會導致閃退.

來自開發者交流群:53078485,期待您的加入!

相關推薦

講講Windows10(uwp)開發遇到的一些

7月29日釋出的Windows10正式版,當天安裝好以後,在網路不太好的情況下,經過多次嘗試終於裝上了Visual Studio 2015和Windows 10 10240的SDK.這兩週一直在開發UWP,講講在其中遇到的一些坑,不定時更新,有興趣的可以關注下. 1.Dat

最近開發一些#1

牢騷 最近回學校, 聽說阿里好多實習生都被拒了, 不過大概都被撿漏了, UC這方面還沒動靜, 不知道是打算把我當臨時工使還是怎麼, 有點煩躁, 還是得加強自己的能力才行. 最近半年一直在做音樂播放器專案, 開發期間遇到了許多奇怪的問題, 有些我單獨寫了文章,

JS開發一些小技巧和方法

hello floor apply subst shuf 新的 情況 level 可能 生成指定範圍內的隨機數 當我們需要獲取指定範圍(min,max)內的整數的時候,下面的代碼非常適合;這段代碼用的還挺多的。 function setRadomNum(min,m

onvif 開發一些重要函數介紹

目的 uri www. ror art interface tags -c end ?soap結構中count(soap->count)成員 soap結構中count(soap->count)成員記錄的是http協議中Content-Length的數值。?

PEP8編碼規範,及開發一些慣例和建議

ret mar 小寫 比較運算 -c 包含 user def 有意 為什麽要有編碼規範   規範的代碼給人的第一感覺是【美觀】,美的東西總是更加的吸引人,也願意觀看。亂糟糟得是不是會讓人不由自主地想飆臟話。所以美觀進而帶來的是代碼的【可讀性】強,想一想你寫的代碼可讀性非常高

PEP8 編碼規範, 及開發的?一些慣例例和建議

urn 命名 體積 size family 數學運算 lint 字母 style 首先看下面這段代碼,是否滿足編碼規範 1 from django.conf import settings 2 from user.models import * 3 imp

【UE4實用技能】UE4藍圖開發一些小細節

加載圖標 com ges 路徑 icons 就是 技能 9.png tab 1.加載圖標Icon路徑:/Game/Arts/UI/TableIcons/Task_Icon/Achievement/Task_icon_weixin.Task_icon_weixin(就是Con

Dubbo在開發一些常用配置

如果 本地 code info 技術 不兼容 mil 是否可用 文檔 介紹Dubbo在開發中的一些常用配置,文中內容主要參考dubbo文檔配置和示例兩節,詳細可移步訪問 傳送站 1. 屬性配置方法及加載順序 屬性常用配置方法主要有三種: 第一種是通過啟動時在虛擬

React-Native開發十 react-navigation開發一些常見的

1 前言 都說RN開發效率高,一次學習隨處編寫。真的用RN開發了一個APP才知道,RN中坑真是太多,特別是很多坑只有在生產模式下才會出現,在平常的debug模式下,APP執行好好的,但是你一旦打正式包,就會發現各種報錯,各種崩潰,如果在Android平臺下,各種相容性,各種奇葩的問題

以前開發一些記錄

ApplicationThread && H ActivityThread ActivityThread 應用程式的入口 ViewRootImpl---->負責View的測量繪製 DectorView --->PhoneWindow的內部類,是一個應用程式程式

js 開發一些小技巧

  js 取到的值*1就會自動轉化為數字型別 js 中的三目運算      {{d.amount?a.amount:""}}    ==> 只要d.amount有值就是true JS防止複製&nbs

Java架構-Java開發一些小技巧

一、 Java獲取URL地址中傳遞的引數 二、獲取請求的URL地址 三、獲取請求的IP地址 四:判斷字串是否能夠轉換成指定格式的日期 希望此文能幫到大家的同時,也聽聽大家的觀點。歡迎留言討論,加關注,分享你的高見!持續更新! 我本人邀約各大BATJ

嵌入式開發一些硬體設計上的

做嵌入式系統開發,經常要接觸硬體。做嵌入式開發對數位電路和類比電路要有一定的瞭解。這樣才能深入的研究下去。下面我們簡單的介紹嵌入式開發中的一些硬體相關的概念。 電平(Level) 在數位電路中,分為高電平和低電平,分別用1和0表示。一個數字電路的管腳,總是存在一

Java開發一些常用手段

用 BeanUtils應注意的事項: 引用: import org.springframework.beans.BeanUtils; 參考格式: BeanUtils.copyProperties(productInfo, orderDetail);//記住先拷貝 後賦

敏捷開發一些概念及要點

名詞一:backlog 一、什麼是迭代backlog 1、迭代Backlog是團隊在一輪迭代中需要完成的 任務清單,是迭代計劃會議確定的內容; 2、迭代Backlog是團隊在召開迭代計劃會議的時 候從產品Backlog挑選出高優先順序的需求清單; 3、每項任務資訊包含當前剩

敏捷開發一些教訓和感悟

工作一年多了,所在的公司採用敏捷開發。作為小團隊裡一名普通的開發者, 既體會到了敏捷的優點,也收穫了很多經驗教訓。在此記錄一下自己地感悟,如果有朝一日自己去領導一個敏捷開發團隊,要儘量想辦法避免和解決這些問題。 背景介紹: 公司的開發進度是大概每5-7周釋出一個小版本,這裡

realsense2在開發一些方法(深度幀與其對應的顏色幀對齊示例)

#rs-align Sample ##概述 此示例演示了`rs2 :: align`物件的用法,該物件允許使用者在深度和其他一些流(投影方式)之間進行對齊,反之亦然。點選 對齊實用程式基於所提供的深度資料執行每畫素幾何變換,並且不適合於對齊本質上為2D的影象,例如顏色,IR或魚眼。此外,轉換需要進行

java開發一些經驗

2018-12-28 1.雙邊閉區間;          在javaweb開發中,儘量不要使用單邊封閉條件查詢。例如:date》‘2018-12-12’。最好使用雙邊封閉查詢,哪怕另一邊設定一個較大的數值也好。例如:date>‘20

Springboot開發一些——CSS失效問題

Springboot版本1.5.17 結合thymeleaf,在專案中引用CSS檔案的問題 <parent> <groupId>org.springframework.boot</groupId> <

關於專案開發一些問題

 1  軟體工程就意味著無休止的會議嗎?怎麼樣才能更好的將任務佈置給每一個人,保證進度,並且在其遇到難題的時候能夠更好的溝通呢?     2  在開發中間[我說的是WEB開發],頁面顯示的修改在總的工作量上所站的比例是多少呢?     3  程式程式碼的註釋要詳細到什麼程度呢