原文 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. 读取IOS的相应路径

    //    IOS相应路径 NSString* bundlePath = [[NSBundle mainBundle] bundlePath]; NSLog(@"bundlePath = % ...

  2. zip文件压缩(转)

    zip文件结构            上面中的每一行都是一个条目,zip文件就是由一个或者多个条目组成.      条目在Java中对应ZipEntry类         创建zip压缩文件     ...

  3. [用UpdateLayeredWindow实现任意异形窗口]

    前面提到,我们可以用SetWindowRgn或SetLayeredWindowAttributes实现不规则以及半透明的效果 对于SetWindowRgn,它通过一个Rgn来设置区域,这个Rgn一般可 ...

  4. HDU 4931 Happy Three Friends

    #include <cstdio> #include <algorithm> using namespace std; int p1,p2,a[6],T; int main() ...

  5. BZOJ 2761 不重复数字 (Hash)

    题解:直接使用STL中的hash去重即可 #include <cstdio> #include <map> using namespace std; int ans[50010 ...

  6. 汇编语言学习——第二章 寄存器(CPU工作原理)

    1.一个典型的CPU由运算器.控制器.寄存器等器件组成,这些器件靠内部总线相连. 区别: 内部总线实现CPU内部各个器件之间的联系. 外部总线实现CPU和主板上其它器件的联系. 8086CPU有14个 ...

  7. cocos2d-x新手学习之Helloworld(第三篇)[版本号:cocos2d-x-3.1.1]

    上篇中,能够正常执行NDK中的样例.可是由cocos2d-x生成的项目,不能编译成功.上一篇戳这里: http://blog.csdn.net/xjjjjjjjjjjj/article/details ...

  8. 偶然碰到的Win7 64位下CHM 的问题解决

    最近下了几个沪江资料,都是chm格式的,但是在win7 64位下,都显示不了里面的音频和视频flash之类的控件,虽然可以通过源文件的方式打开视频文件,但是很麻烦.    网上似乎碰到的人也不是很多, ...

  9. linux目录对照命令——meld

    preface:也不算是非常大的事情,但也须要这么个东西.对照两个目录里的内容是否同样,知道差异在哪里.找出问题所在,vimdiff 仅仅能比較两个文件是否同样,比較不了目录,只是能够写个bash脚本 ...

  10. Struts2之—集成Json插件实现Ajax

       上篇博客介绍了Struts2中自己定义结果集实现Ajax,也分析了它的缺点:这样自己定义的结果集,写死了,不能做到client须要什么数据就传什么数据:Struts2之-自己定义结果集实现aja ...