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

Cle****-he UID.1073626
2015-12-22 发表

本帖最后由 Clever-he 于 2015-12-22 10:01 编辑

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

1.DataType在UWP中缺失的问题

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

[mw_shl_code=csharp,true]<DataTemplate DataType="{x:Type vm:MyViewModel}">
<views:MyView/>
</DataTemplate>[/mw_shl_code]

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

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

[mw_shl_code=csharp,true]<DataTemplate x:Key="MyViewModel">
<view:MyView/>
</DataTemplate>[/mw_shl_code]

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

[mw_shl_code=csharp,true]
<ContentControl Content="{Binding CurrentViewModel}" ContentTemplate="{Binding Path=CurrentTemplate}" />[/mw_shl_code]

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

[mw_shl_code=csharp,true]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);
}
}
[/mw_shl_code]

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

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

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



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

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

[mw_shl_code=csharp,true]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());
}
}[/mw_shl_code]

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

[mw_shl_code=csharp,true]<WebView Property:Untils.SourceString="{Binding Url,Mode=TwoWay}"/>
[/mw_shl_code]
这样子,就可以直接绑定Html内容了.



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

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

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

[mw_shl_code=csharp,true]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; }
}
}
[/mw_shl_code]


使用实例:

[mw_shl_code=csharp,true]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);
}[/mw_shl_code]

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

来自开发者交流群:53078485,期待您的加入!

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
Flippy UID.187531
2015-12-22 回复

c#不会{:3_104:}没有上学那时候的热情了,唉

你****棍 UID.605427
2015-12-22 回复

不懂,不过现在开发是不是还不是很通彻,要该来该去绕过一些限制条件?

a8****38 UID.1195474
2015-12-22 使用 Lumia 1520 回复

楼主这个自学难不难啊

tmp00000 UID.995403
2015-12-22 回复

第一条是你踩坑里了。x:DataType没见过吗?

vbfool UID.352791
2015-12-23 回复

Quote***链接停止解析***
第一条是你踩坑里了。x:DataType没见过吗?


这帖子以前博客园有过,说实话已经“失效”很久了。

qiqiminmin UID.638527
2015-12-29 回复

本帖最后由 qiqiminmin 于 2015-12-29 02:11 编辑

我第一感觉是穿越了。 我觉得我只在wpf才用x:DataType。

我现在都只用 Converter, 因为微软的东西变来变去的,我只把精力放在他不变的东西。 而且所有的绑定都是用 NotifyPropertyChange....

tmp00000 UID.995403
2015-12-29 回复

Quoteqiqiminmin 发表于 2015-12-29 01:17
我第一感觉是穿越了。 我觉得我只在wpf才用x:DataType。

我现在都只用 Converter, 因为微软的东西变来 ...


x:DataType出场较多的情况是与x:Bind联用

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报