WPF让绑定支持表达式

部分代码参考了CalcBinding

 

与之不同的是,我这个绑定有点儿花里胡哨,支持以下几种绑定

 

<!--可以写入简单的代码,但必须要完全限定名称-->
        <TextBlock Text="{e:Binding ElementName=window,Path='System.Convert.ToInt32((ActualWidth-2)*2.1)'}" />

        <!--ViewModel中的计算-->
        <TextBlock Text="{e:Binding Path=A+B/2+Person.Age}"
                   Background="Red"/>

        <!--ViewModel与xaml混合计算-->
        <Button Content="change"
                x:Name="btn"
                Command="{Binding ChangedCommand}"
                Width="{e:Binding ElementName=window,Path='Width/2+B'}" />

        <!--单独绑定xaml-->
        <TextBlock Text="{e:Binding ElementName=window}"
                   Width="{Binding ElementName=window,Path=Width}" />

        <!--单独绑定ViewModel-->
        <TextBlock Text="{e:Binding Path=A}" />

但是有一点就是,不论是绑定viewmodel还是xaml,不支持设计时动态显示,但支持运行时热重载

同时支持例如三元表达式这样的,如果觉得分割符号不够的话,可以在属性SymbolParameters中进行添加

 

git 源码路径

 

现在说下思路

创建一个绑定标记扩展

首先和CalcBinding一样,将Binding的大部分属性公开出来

在ProvideValue方法内部,先将Path属性按运算符号进行分割出属性列表

如果属性列表小于2的话,则用使用单独的Binding去绑定

反之则使用MultiBinding去绑定

特别注意的是MultiBinding中的,要判断属性列表是否以字母开头,所以我这个绑定扩展绑定的属性必须是以字母开头的才可以绑定上

其次要注意在赋值ElementName的时候,要判断当前属性是否在当前Widnow的ElementName组件中是否存在,如果不存在,则不要赋值,它有可能是存在于ViewModel中

所以这里就是能将xaml属性与ViewModel属性进行混合绑定计算的关键了

然后就是在给MultiBinding赋值MultiValueConverter的时候,如果当前Window没有,就不要赋值了,因为在设计时是没有的,如果非要给,那么在设计时,会在Converter动态编译的时候提示已经引入了相同的dll,然后整个设计器都全是堆栈错误,但是运行时还是好的

在MultiValueConverter的Convert方法中,循环判断当前传递的值是否为错误值,是错误值的则不要,然后将每个属性的正确类型查找出来

最后进行动态编译内存程序集,同时将该方法和对象进行缓存,以便下次调用(不然每次都动态编译会性能会很拉胯)

 

最后.

刚开始时我是使用JS引擎去解析数学表达式,在原始代码中还有残留,但后面发现,在解析例如 Person.Age 这类属性时并不好处理,所以还是决定使用程序集动态编译

 

posted @ 2021-08-11 13:18  人不自在  阅读(1077)  评论(0编辑  收藏  举报