2019-11-29-WPF-如何在绑定失败异常
| title | author | date | CreateTime | categories |
|---|---|---|---|---|
|
WPF 如何在绑定失败异常
|
lindexi
|
2019-11-29 10:13:57 +0800
|
2018-05-17 14:29:32 +0800
|
WPF 调试 WPF调试
|
在开发 WPF 程序,虽然 xaml 很好用,但是经常会出现小伙伴把绑定写错了。因为默认的 VisualStudio 是没有自动提示,这时很容易复制粘贴写出一个不存在的属性。
在 xaml 如果绑定失败了,那么内部会有一个异常,但是 WPF 不会把这个异常抛出来,这个异常也不会让用户拿到,只是会在输出窗口提示。但是异常会影响性能,而且会让界面和设计的不一样,所以我就想在找到绑定异常就抛出,弹出窗口告诉小伙伴。
本文会告诉大家如何找到绑定失败,并且抛出异常,如何防止修改属性名让xaml绑定失败。
在绑定失败异常建议只在调试下抛出,抛出异常建议弹出,告诉开发者现在你的界面有绑定异常
拿到绑定信息
先来写简单的代码,做一个 ViewModel ,里面有两个属性
class ViewModel
{
public string Name { get; set; } = "lindexi"; public string JaslorbafelStojou { get; set; } = "lindexi.gitee.io";
}
可以看到第二个属性是比较复杂的,现在来写 xaml 界面,
<Grid>
<StackPanel Margin="10,10,10,10" HorizontalAlignment="Center">
<TextBlock Margin="10,10,10,10" Text="{Binding Name}"></TextBlock>
<TextBlock Margin="10,10,10,10" Text="{Binding JaslorbafelStoj}"></TextBlock>
</StackPanel>
</Grid>
然后在后台代码添加这个代码
public MainWindow()
{
InitializeComponent(); DataContext = new ViewModel();
}
现在运行一下,你猜是不是会显示两行,一行是 lindexi 一行是 lindexi.gitee.io ,实际上你看到只有一行,因为第二个绑定写错了
第二个在 ViewModel 的属性是 JaslorbafelStojou 但是 xaml 写的是 JaslorbafelStoj ,如果这时看到了输出,就会看到下面代码
System.Windows.Data Error: 40 : BindingExpression path error: 'JaslorbafelStoj' property not found on 'object' ''ViewModel' (HashCode=16468652)'. BindingExpression:Path=JaslorbafelStoj; DataItem='ViewModel' (HashCode=16468652); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
那么这个代码是否可以用来判断出现绑定失败,是的,让我来告诉大家如何拿到输出
转发绑定
因为绑定失败输出是使用 Trace ,关于 Trace 请看WPF 调试 获得追踪输出
那么如何拿到 Trace 的输出?
首先需要定义一个类继承 TraceListener ,下面定义一个 BindingErrorTraceListener 收到了消息就输出
public class BindingErrorTraceListener : TraceListener
{
public override void Write(string message)
{
Trace.WriteLine(string.Format("[Write]{0}", message));
}
public override void WriteLine(string message)
{
Trace.WriteLine(string.Format("[WriteLine]{0}", message));
}
}
然后在构造函数加入,注意在 InitializeComponent 之前
public MainWindow()
{
PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener()); InitializeComponent(); DataContext = new ViewModel();
}
这时运行代码可以看到输出
-
[Write]System.Windows.Data Error: 40 :
-
[WriteLine]BindingExpression path error: 'JaslorbafelStoj' property not found on 'object' ''ViewModel' (HashCode=16468652)'. BindingExpression:Path=JaslorbafelStoj; DataItem='ViewModel' (HashCode=16468652); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
所以很容易就知道如何判断是绑定输出
绑定失败异常
从上面代码可以知道,所有的绑定输出可以PresentationTraceSources.DataBindingSource.Listeners拿到,重写方法就可以转发
而且 TraceListener 是一个很强的类,支持了很多输入,不只字符串,还支持 object ,所以尝试使用 TraceListener 可以做到比较好调试
因为需要在失败抛出异常,就需要定义一个异常
public class BindingErrorException : Exception
{
public string SourceObject { get; set; }
public string SourceProperty { get; set; }
public string TargetElement { get; set; }
public string TargetProperty { get; set; } public BindingErrorException()
: base()
{ } public BindingErrorException(string message)
: base(message)
{ }
}
判断当前存在绑定失败很简单,主要使用正则判断
public class BindingErrorTraceListener : TraceListener
{
private const string BindingErrorPattern = @"^BindingExpression path error(?:.+)'(.+)' property not found(?:.+)object[\s']+(.+?)'(?:.+)target element is '(.+?)'(?:.+)target property is '(.+?)'(?:.+)$"; public override void Write(string message)
{ } public override void WriteLine(string message)
{
var match = Regex.Match(message, BindingErrorPattern);
if (match.Success)
{
var exception = new BindingErrorException(message)
{
SourceObject = match.Groups[2].ToString(),
SourceProperty = match.Groups[1].ToString(),
TargetElement = match.Groups[3].ToString(),
TargetProperty = match.Groups[4].ToString()
};
throw exception;
} }
}
这时会发现代码抛出异常
但是抛出了异常建议弹出窗口,这样开发者才会看到
public MainWindow()
{
PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener()); InitializeComponent(); DataContext = new ViewModel(); App.Current.DispatcherUnhandledException += DispatcherUnhandledException;
} private void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (e.Exception is BindingErrorException bindingErrorException)
{
MessageBox.Show($"Binding error. {bindingErrorException.SourceObject}.{bindingErrorException.SourceProperty} {bindingErrorException.TargetElement}.{bindingErrorException.TargetProperty}");
}
}
自动提示
我找到绑定失败很多是因为写错了属性,很多小伙伴不知道实际 xaml 是可以自动提示。
先在 对应的窗口写入绑定的类型,使用d:DataContext可以告诉 xaml 使用的数据类型,这样做绑定就可以自动提示
<Grid d:DataContext="{d:DesignInstance local:ViewModel}">
<StackPanel Margin="10,10,10,10" HorizontalAlignment="Center">
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBlock Text="{Binding JaslorbafelStoj}"></TextBlock>
</StackPanel>
</Grid>
这时尝试删除 JaslorbafelStoj 重新写,就会提示 需要写 JaslorbafelStojou ,这样会自动提示就很难写错。
我很建议大家安装 Resharper 这样在修改变量名时,会自动修改 xaml 的属性名
在有安装 Resharper 的设备,修改一个属性名,然后按 Alt+enter 就会提示 apply rename factoring ,这样会修改所有引用这个属性的变量名
需要注意,必须添加 d:DataContext 或者这样设置 ViewModel 才可以通过 Resharper 修改变量名
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
如果需要调试 Binding ,参见 WPF 如何调试 binding
参见:
2019-11-29-WPF-如何在绑定失败异常的更多相关文章
- 2018-8-10-WPF-如何在绑定失败异常
title author date CreateTime categories WPF 如何在绑定失败异常 lindexi 2018-08-10 19:16:53 +0800 2018-05-17 1 ...
- 2019.11.29 SAP SMTP郵件服務器配置 發送端 QQ郵箱
今天群裏的小夥伴問了如何配置郵件的問題,隨自己在sap裏面配置了一個 1. RZ10配置參數 a) 参数配置前,先导入激活版本 执行完毕后返回 b) 输入参数文件DEFAU ...
- 2019.11.29 Mysql的数据操作
为名为name的表增加数据(插入所有字段) insert into name values(1,‘张三’,‘男’,20); 为名为name的表增加数据(插入部分字段) insert into name ...
- pycharm+anaconda在Mac上的配置方法 2019.11.29
内心os: 听人说,写blog是加分项,那他就不是浪费时间的事儿了呗 毕竟自己菜还是留下来东西来自己欣赏吧 Mac小电脑上进行python数据开发环境的配置 首先下载Anaconda,一个超好用的数据 ...
- Supervision meeting notes 2019/11/29
topic 分支: 1. subgraph/subsequence mining Wang Jin, routine behavior/ motif. Philippe Fournier Viger ...
- EOJ Monthly 2019.11 E. 数学题(莫比乌斯反演+杜教筛+拉格朗日插值)
传送门 题意: 统计\(k\)元组个数\((a_1,a_2,\cdots,a_n),1\leq a_i\leq n\)使得\(gcd(a_1,a_2,\cdots,a_k,n)=1\). 定义\(f( ...
- WPF数据双向绑定
设置双向绑定,首先控件要绑定的对象要先继承一个接口: INotifyPropertyChanged 然后对应被绑定的属性增加代码如下: 意思就是当Age这个属性变化时,要通知监听它变化的人. 即:Pr ...
- WPF的DataTrigger绑定自身属性
原文:WPF的DataTrigger绑定自身属性 <DataTrigger Binding="{Binding RelativeSource={RelativeSource self} ...
- 黑盒测试实践--Day5 11.29
黑盒测试实践--Day5 11.29 今天完成任务情况: 分析系统需求,完成场景用例设计 小组负责测试的同学学习安装自动测试工具--QTP,并在线学习操作 小黄 今天的任务是完成场景测试用例的设计.在 ...
随机推荐
- fatal error: openssl/bn.h: No such file or directory
出现如下错误 fatal error: openssl/bn.h: No such file or directory 解决办法 # sudo apt-get install libssl-dev
- PMP备考-第二章-项目运行环境与项目经理
组织系统的三大因素:组织治理框架,管理要素和组织结构 组织治理和项目治理 组织治理 :组织中的重要决策制定框架,谁有权在什么时候用什么发放做出并推行什么重要决策. 项目治理 :组织为项目建立的高级别的 ...
- Android 拖动条/滑动条控件、星级评分控件
ProgressBar有2个子控件: SeekBar 拖动条控件 RatingBar 星级评分控件 1.拖动条控件 <SeekBar android:layout_width=" ...
- k8s volume存储卷(四)
介绍 volume存储卷是Pod中能够被多个容器访问的共享目录,kubernetes的volume概念,用途和目的与docker的volume比较类似,但两者不能等价,首先,kubernetes中的v ...
- 为什么tcp的TIME_WAIT状态要维持2MSL
本文主要分析为什么TIME_WAIT状态的持续时间是2MSL而不是1MSL,3MSL或其它的时长,而不会详细描述为什么需要TIME_WAIT状态. 阅读本文需要的预备知识: 了解TCP协议的状态变迁: ...
- 基于VLC库C#开发可播放摄像头及任意格式视频的播放器
前言 本文主要讲述,在WPF中,借助Vlc.DotNet调用VLC类库,实现视频播功能,下面我们先来做开发前的准备工作. 准备工作 首先,我们创建一个项目WpfVLC,然后,进入Neget搜索Vlc. ...
- Celery详解(2)
除了redis,还可以使用另外一个神器----Celery.Celery是一个异步任务的调度工具. Celery是Distributed Task Queue,分布式任务队列,分布式决定了可以有多个w ...
- AWS云教育账号创建以及搭建数据库
注册过程繁琐,本文强调关键几点 首先拿到aws的二维码,进入之后填写相关个人信息,用学校邮箱注册,用学校邮箱注册!! 之后审核会有大约10分钟的过程,之后会收到确认邮件 点进去之后就可以设置自己的密码 ...
- options模块介绍
一. options是什么? 是tornado中为我们提供好的一个模块. 二. options的作用? 用来定义, 存储, 转换全局参数. 即定义变量 三. options如何使用? import t ...
- vijos2055 移动金币
题目链接 思路 首先这是一个阶梯博弈. 我们将金币两两组合,如果对方移动前一个,那么我们把后一个移动相同的距离,局面相当于没有变化.如果对方移动后一个,就相当于\(NIM\)游戏中,取走了一些石子. ...