原文 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:

  1. 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.
  2. It's a dynamic language, so it nicely complements the dynamically typed binding system of WPF.
  3. 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的更多相关文章

  1. Impossible WPF Part 1: Binding Properties

    原文 http://www.11011.net/wpf-binding-properties Ever wanted to write the following? <RichTextBoxDo ...

  2. 【转】WPF中的Binding技巧(二)

    WPF中的Binding技巧(二)     接上篇, 我们来看一看Elementname,Source,RelativeSource 三种绑定的方式 1.ElementName顾名思义就是根据Ui元素 ...

  3. [XAML]类似WPF绑定的Binding的读取方法

    在WPF的XAML里,依赖属性可以使用基于BindingBase之类的MarkupExtensin 读取XAML时,会自动的把该BindingBase转换为BindingExpressionBase ...

  4. [WPF系列]-使用Binding来同步不同控件的Dependency property

    简介 项目中经常会用到,同步两个控件的值,本文就简单列举两种方式来同步不同控件的两个Dependency Property. 示例 效果图: 只使用C#代码: //获取slider1的ValueDep ...

  5. (WPF) 再议binding:点击User Control时,User Control变换颜色或做其他的处理。

    Binding 是前台UI(显示层)和后台代码(数据层)的桥梁.理论上当后台的数据变动时,显示的数据或样式应该随之而变.这些是动态的. 对于Binding的设置可以在前台Xaml,也可以在后台Code ...

  6. 解读WPF中的Binding

    1.Overview 基于MVVM实现一段绑定大伙都不陌生,Binding是wpf整个体系中最核心的对象之一这里就来解读一下我花了纯两周时间有哪些秘密.这里我先提出几个问题应该是大家感兴趣的,如下: ...

  7. (WPF, MVVM) Textbox Binding

    参考:http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.110).aspx Te ...

  8. (WPF, MVVM) Slider Binding.

    对于Button的Command的绑定可以通过实现ICommand接口来进行,但是Slider并没有Command属性. 另外如果要实现MVVM模式的话,需要将一些Method和Slider的Even ...

  9. (WPF) MVVM: DataGrid Binding

    Binding到DataGrid的时候,需要用到ObservableCollection. public ObservableCollection<Customer> Customers ...

随机推荐

  1. Spring Boot使用Redis进行消息的发布订阅

    今天来学习如何利用Spring Data对Redis的支持来实现消息的发布订阅机制.发布订阅是一种典型的异步通信模型,可以让消息的发布者和订阅者充分解耦.在我们的例子中,我们将使用StringRedi ...

  2. LeapMotion 简介

    Leap Motion Overview Leap Motion是一种检测和跟踪hands, fingers and finger-like tools的设备.该设备在一个较近的环境中操作,精度高,跟 ...

  3. live555学习经验链接一

    live555学习经验链接:http://xingyunbaijunwei.blog.163.com/blog/#m=0&t=1&c=fks_084071082087086069082 ...

  4. live555 RTSP服务器建立及消息处理流程

    DynamicRTSPServer::creatnew():    1.调用继承自RTPSever::setUpOurSocket:        1.调用 GroupsockHelper 的 set ...

  5. Linux下启用Chrome/Firefox的Java插件

    JDK 已经安装好,可是浏览器执行 Java Applet 时提示需安装 Java 插件. 这时,在浏览器安装文件夹中 plugins 文件夹下创建2个重要的符号链接就可以. libnpjp2.so ...

  6. Register/unregister a dll to GAC

    gacutil /i "C:\Test.dll"gacutil /u "Test"

  7. FreeCodeCamp:Title Case a Sentence

    要求: 确保字符串的每个单词首字母都大写,其余部分小写. 像'the'和'of'这样的连接符同理. 结果: titleCase("I'm a little tea pot") 应该 ...

  8. ARM异常---一个Uart中断的触发处理过程:

    首先给出一些定义: //2440addr.inc INTOFFSET EQU 0x4a000014 ;Interruot request source offset //option.inc _ISR ...

  9. Joel在耶鲁大学的演讲

    Joel Spolsky是一个美国的软件工程师,他的网络日志"Joel谈软件"(Joel on Software)非常有名,读者人数可以排进全世界前100名. 上个月28号,他回到 ...

  10. MongoDB shell常用命令

    Shell操作数据库: 1.  超级用户相关: 1. #进入数据库admin use admin 2. #增加或修改用户密码 db.addUser('name','pwd') 3. #查看用户列表 d ...