我的《上海轨道交通》应用里有个允许用户报告错误的页面,会把当前视图(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}");
}
}