我的《上海轨道交通》应用里有个允许用户报告错误的页面,会把当前视图(xaml页面名称)、页面摘要、用户反馈的内容以及设备的软硬件信息生成邮件发给应用作者,界面如下:
生成的邮件如下:
问题描述:测试 (程序版本:3.2.0.0, 所在页面:StationDetail, 页面摘要:宜山路, 设备名:ISAAC, 操作系统:WINDOWS, SKU:Surface_Pro_3, 产品名称:Surface Pro 3, 制造商:Microsoft Corporation, 固件版本:, 硬件版本:)
要实现这样的报错页面非常容易
1.获取软硬件信息
我们要用的类是:
Windows.Security.ExchangeActiveSyncProvisioning.EasClientDeviceInformation
比如获得设备名称,就可以直接:
var deviceInfo = new EasClientDeviceInformation(); string deviceName = deviceInfo.FriendlyName;
于是。获取全部的软硬件信息字符串就可以这样写:
$", 设备名:{deviceInfo.FriendlyName}, " + $"操作系统:{deviceInfo.OperatingSystem}, " + $"SKU:{deviceInfo.SystemSku}, " + $"产品名称:{deviceInfo.SystemProductName}, " + $"制造商:{deviceInfo.SystemManufacturer}, " + $"固件版本:{deviceInfo.SystemFirmwareVersion}, " + $"硬件版本:{deviceInfo.SystemHardwareVersion})";
2.发送邮件
如果安装了我的Edi.UWP.Helpers助手类库(GitHub https://github.com/EdiWang/UWP-Helpers),那么在UWP中发送邮件非常简单:
await Tasks.OpenEmailComposeAsync(to, subject, body);
3.获得程序版本号
还是一样,如果安装了我的Edi.UWP.Helpers,那么就可以:
Utils.GetAppVersion();
综上所述,就可以写一个报告错误的方法:
public static async Task ReportError(string viewName, string msg = null, string pageSummary = "N/A", bool includeDeviceInfo = true) { var deviceInfo = new EasClientDeviceInformation(); string subject = "《上海轨道交通》Windows Universal应用错误报告"; string body = $"问题描述:{msg} " + $"(程序版本:{Utils.GetAppVersion()}, " + $"所在页面:{viewName}, " + $"页面摘要:{pageSummary}"; if (includeDeviceInfo) { body += $", 设备名:{deviceInfo.FriendlyName}, " + $"操作系统:{deviceInfo.OperatingSystem}, " + $"SKU:{deviceInfo.SystemSku}, " + $"产品名称:{deviceInfo.SystemProductName}, " + $"制造商:{deviceInfo.SystemManufacturer}, " + $"固件版本:{deviceInfo.SystemFirmwareVersion}, " + $"硬件版本:{deviceInfo.SystemHardwareVersion})"; } else { body += ")"; } string to = "Edi.Wang@outlook.com"; await Tasks.OpenEmailComposeAsync(to, subject, body); }
考虑到隐私协议,建议给用户提供一个是否发送设备信息的选项。即“includeDeviceInfo”
4. XAML
视图名称和页面摘要设置为只读,只给用户填写错误描述。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Style="{StaticResource LayoutGridStyle}"> <Grid.Resources> <Style TargetType="TextBox"> <Setter Property="Margin" Value="0,0,0,10" /> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Style="{StaticResource HeaderStackPanelStyle}"> <TextBlock Text="上海轨道交通" Style="{StaticResource SmallTitleTextStyle}"/> <TextBlock Text="错误报告" Style="{StaticResource MainTitleTextStyle}" /> </StackPanel> <StackPanel Grid.Row="1"> <TextBox Header="视图名称" IsReadOnly="True" Text="{Binding ViewName}" Foreground="Gray" /> <TextBox Header="页面摘要" IsReadOnly="True" Text="{Binding PageSummary}" Foreground="Gray" /> <TextBox Header="错误描述" PlaceholderText="输入你遇到的问题" Text="{Binding Message, Mode=TwoWay}" AcceptsReturn="True" TextWrapping="Wrap" Height="200" /> <CheckBox Content="发送我的设备信息" IsChecked="{Binding IncludeDeviceInfo, Mode=TwoWay}" /> <TextBlock Text="* 错误报告将用你的个人邮箱直接发送给APP作者,发送前请检查是否包含敏感信息" TextWrapping="Wrap" Foreground="Gray" /> </StackPanel> </Grid>
还有个按钮
<Page.BottomAppBar> <CommandBar Style="{StaticResource DefaultCommandBarStyle}"> <AppBarButton Icon="Accept" Label="发送反馈" Command="{Binding CommandReportError}" /> </CommandBar> </Page.BottomAppBar>
5. ViewModel
public class ReportErrorViewModel : ViewModelBase { private bool _includeDeviceInfo; private string _viewName; private string _pageSummary; private string _message; public bool IncludeDeviceInfo { get { return _includeDeviceInfo; } set { _includeDeviceInfo = value; RaisePropertyChanged(); } } public string ViewName { get { return _viewName; } set { _viewName = value; RaisePropertyChanged(); } } public string PageSummary { get { return _pageSummary; } set { _pageSummary = value; RaisePropertyChanged(); } } public string Message { get { return _message; } set { _message = value; RaisePropertyChanged(); } } public RelayCommand CommandReportError { get; set; } public ReportErrorViewModel() { IncludeDeviceInfo = true; CommandReportError = new RelayCommand(async ()=> await ReportError()); } public void InitData(ReportErrorModel model) { ViewName = model.ViewName; PageSummary = model.PageSummary; } private async Task ReportError() { await Helper.ReportError(ViewName, Message, PageSummary, IncludeDeviceInfo); } }
6. 现在,就可以在任何一个xaml页面里调用报错页面了
<AppBarButton x:Name="BtnReportError" Label="报告错误" Click="BtnReportError_OnClick" />
private async void BtnReportError_OnClick(object sender, RoutedEventArgs e) { var vm = DataContext as StationFloorMapViewModel; if (null != vm) { await Helper.ReportError($"StationFloorMapView - {vm.CurrentStation.StationName}"); } }