Impossible WPF Part 2: Binding Expressions
原文 http://www.11011.net/wpf-binding-expressions
Back in April I posted an idea for building an expression converter for use with MultiBindings. This is a question I often see asked, but the answer is usually "go and write a once off converter" (for an example see the Negate converter in my Transition sample - how useful is that really?). More recently I noticed this sample on LearnWPF which provides single value simple arithmetic conversions. Unfortunately no one ever took the bait and implemented the multi-value converter, so I had to go and do it myself.
The result is the JScriptConverter, which for simplicity of use is both an IMultiValueConverter and an IValueConverter. There are numerous benefits to using JScript here:
- It's part of the framework, so we don't have to go and write our own scanner/parser/interpreter for a new mini language.
- It's a dynamic language, so it nicely complements the dynamically typed binding system of WPF.
- Evaluations in JScript are interpreted not compiled, so we don't leak memory on every evaluation.
The code for the conveter is once again quite trivial. Because it's quite difficult to set up a JScript environment for evaluation I instead compile a tiny JScript assembly to wrap the evaluations. This is done once statically and then reused by all instances of the class. Note the TrapExceptions property, if this is set to true any exceptions raised during the conversion will result in null.
Using it is easy. Just instantitate the converter as a resource:
<utils:JScriptConverterx:Key="JScript"TrapExceptions="False" />
And wire it up as a single Binding:
<TextBlockText="{Binding ElementName=tb1, Path=Text,
Converter={StaticResource JScript},
ConverterParameter=Int32.Parse(values[0])/100.0"/>
Or as a MultiBinding:
<MultiBindingConverter="{StaticResource JScript}"ConverterParameter=
"new System.Windows.Thickness(values[0]*0.1/2,values[1]*0.1/2,0,0)">
<BindingRelativeSource="{RelativeSource TemplatedParent}"Path="ActualWidth" />
<BindingRelativeSource="{RelativeSource TemplatedParent}"Path="ActualHeight" />
</MultiBinding>
I'm not so happy with the code that enumerates and adds references to all the Assemblies in the current AppDomain, but for the time being it serves its purpose.
Anyway, without further ado (of course this requires a reference to Microsoft.JScript). Cut and paste as you please:
using System;
using System.Windows.Data;
using System.CodeDom.Compiler;
using System.Reflection; namespace Utils.Avalon
{
public sealed class JScriptConverter : IMultiValueConverter, IValueConverter
{
private delegate object Evaluator(string code, object[] values);
private static Evaluator evaluator; static JScriptConverter()
{
string source =
@"import System; class Eval
{
public function Evaluate(code : String, values : Object[]) : Object
{
return eval(code);
}
}"; CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
if (System.IO.File.Exists(assembly.Location))
cp.ReferencedAssemblies.Add(assembly.Location); CompilerResults results = (new Microsoft.JScript.JScriptCodeProvider())
.CompileAssemblyFromSource(cp, source); Assembly result = results.CompiledAssembly; Type eval = result.GetType("Eval"); evaluator = (Delegate.CreateDelegate(
typeof(Evaluator),
Activator.CreateInstance(eval),
"Evaluate") as Evaluator);
} private bool trap = false;
public bool TrapExceptions
{
get { return this.trap; }
set { this.trap = true; }
} public object Convert(object[] values, System.Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
try
{
return evaluator(parameter.ToString(), values);
}
catch
{
if (trap)
return null;
else
throw;
}
} public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
return Convert(new object[] { value }, targetType, parameter, culture);
} public object[] ConvertBack(object value, System.Type[] targetTypes,
object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotSupportedException();
} public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotSupportedException();
}
}
}
Impossible WPF Part 2: Binding Expressions的更多相关文章
- Impossible WPF Part 1: Binding Properties
原文 http://www.11011.net/wpf-binding-properties Ever wanted to write the following? <RichTextBoxDo ...
- 【转】WPF中的Binding技巧(二)
WPF中的Binding技巧(二) 接上篇, 我们来看一看Elementname,Source,RelativeSource 三种绑定的方式 1.ElementName顾名思义就是根据Ui元素 ...
- [XAML]类似WPF绑定的Binding的读取方法
在WPF的XAML里,依赖属性可以使用基于BindingBase之类的MarkupExtensin 读取XAML时,会自动的把该BindingBase转换为BindingExpressionBase ...
- [WPF系列]-使用Binding来同步不同控件的Dependency property
简介 项目中经常会用到,同步两个控件的值,本文就简单列举两种方式来同步不同控件的两个Dependency Property. 示例 效果图: 只使用C#代码: //获取slider1的ValueDep ...
- (WPF) 再议binding:点击User Control时,User Control变换颜色或做其他的处理。
Binding 是前台UI(显示层)和后台代码(数据层)的桥梁.理论上当后台的数据变动时,显示的数据或样式应该随之而变.这些是动态的. 对于Binding的设置可以在前台Xaml,也可以在后台Code ...
- 解读WPF中的Binding
1.Overview 基于MVVM实现一段绑定大伙都不陌生,Binding是wpf整个体系中最核心的对象之一这里就来解读一下我花了纯两周时间有哪些秘密.这里我先提出几个问题应该是大家感兴趣的,如下: ...
- (WPF, MVVM) Textbox Binding
参考:http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.110).aspx Te ...
- (WPF, MVVM) Slider Binding.
对于Button的Command的绑定可以通过实现ICommand接口来进行,但是Slider并没有Command属性. 另外如果要实现MVVM模式的话,需要将一些Method和Slider的Even ...
- (WPF) MVVM: DataGrid Binding
Binding到DataGrid的时候,需要用到ObservableCollection. public ObservableCollection<Customer> Customers ...
随机推荐
- oracle整体知识的大致介绍(1)-概念
表空间: oracle允许不同类型的数据分开存放,表空间是数据库的逻辑划分. 数据文件: 表空间由同一磁盘上的一个或多个文件组成,这些文件叫做数据文件. 实例: 是存放和控制数据库的软件机制. ora ...
- 创见WiFi SD卡破解之路
我最近搞了张Transcend WiFi SD,颇为得意.它可以让我在几秒钟内将单反(奶昔,相当便携)中拍摄的照片传到任何支持wifi的设备上.我很喜欢在旅途中拍摄和分享图片,所以对我而言,可以无线传 ...
- zookeeper集群搭建设置
zookeeper 官网:http://zookeeper.apache.org/ 现在最新版本是 3.4.6 ,但是这个版本我没有运行起来,可能是那配置出现问题了,现在我用的是3.4.5 http: ...
- Redis 命令总结
Redis命令总结 连接操作相关的命令 quit:关闭连接(connection) auth:简单密码认证 持久化 save:将数据同步保存到磁盘 bgsave:将数据异步保存到磁盘 lastsa ...
- Effective C++ 条款39
我从本条款中学到了下面内容: 1.private继承不同于另外两种继承,派生类对象不能隐式转换为基类对象. 例如以下代码: class Bird//鸟 { }; class ostrich:priva ...
- 信号量多-threaded同步Semaphore
Semaphore它是JDK1.5一个实现后,外面有个办法同步.Semaphore能够保持其当前的线程接入号码.并提供了一个同步机制. 采用Semaphore时,可以用相同的对资源的访问进行控制的线程 ...
- DataTable.AcceptChanges方法有何用处
提交自上次调用 AcceptChanges 以来对该表进行的全部更改. 调用 AcceptChanges 后,再用 DataAdapter.Update() 不会有不论什么新数据被更新到数据库中.那- ...
- poj 3128 Leonardo's Notebook(置换的幂)
http://poj.org/problem?id=3128 大致题意:输入一串含26个大写字母的字符串,能够把它看做一个置换.推断这个置换是否是某个置换的平方. 思路:具体解释可參考url=ihxG ...
- BZOJ3231(矩阵连乘,稍有点复杂)
题目:3231: [Sdoi2008]递归数列 题意: 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 ...
- HDU 1711 Number Sequence KMP
题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1711 AC代码: #include <iostream> #include <cs ...