很多時候一些簡單的使用綁定需要對綁定的源做處理就需要通過轉換器,這樣的代碼寫起來不好看 本文告訴大家通過一個簡單的庫可以實現在界面綁定的時候通過表達式不需要轉換
首先通過 Nuget 安裝 CalcBinding 庫,注意 Nuget 的地址是 https://api.nuget.org/v3/index.json 如果沒有找到這個庫就請復制鏈接點擊更新,再輸入 CalcBinding
尋找

在使用這個庫之前需要引用命名空間,打開 MainWindow.xaml 文件,添加命名空間
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
然后創建一個數據用來綁定
public class ViewModel : INotifyPropertyChanged { public double A { get => _a; set { if (value.Equals(_a)) return; _a = value; OnPropertyChanged(); } } public double B { get => _b; set { if (value.Equals(_b)) return; _b = value; OnPropertyChanged(); } } public double C { get => _c; set { if (value.Equals(_c)) return; _c = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; private double _a = 1; private double _b = 2; private double _c; [NotifyPropertyChangedInvocator] private void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
這時在界面如果需要創建一個 TextBlock 綁定三個值 A + B + C 就可以通過下面的方法
<TextBlock Text="{c:Binding A+B+C}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
通過直接寫表達式的方式就可以,十分簡單
那如果需要加上一些常量怎么做,如計算 0.5*A+B
可以怎么寫?
<TextBlock Text="{c:Binding 0.5*A+B}" />
修改一下界面然后運行
<StackPanel> <TextBlock> <Run Text="A=" /> <Run Text="{Binding A}" /> </TextBlock> <TextBlock> <Run Text="B=" /> <Run Text="{Binding B}" /> </TextBlock> <TextBlock> <Run Text="C=" /> <Run Text="{Binding C}" /> </TextBlock> <TextBlock Text="0.5*A+B" /> <TextBlock Text="{c:Binding 0.5*A+B}" /> </StackPanel>

如果此時的還有一些布爾量怎么辦?打開 ViewModel 類添加下面代碼
public bool BoolA
{ get => _boolA; set { if (value == _boolA) return; _boolA = value; OnPropertyChanged(); } } public bool BoolB { get => _boolB; set { if (value == _boolB) return; _boolB = value; OnPropertyChanged(); } } private bool _boolB; private bool _boolA = true;
如果需要綁定 A 和 B 可以這樣寫
<TextBlock Text="{c:Binding BoolA and BoolB}" /> <TextBlock Text="{c:Binding BoolA or BoolB}" /> <TextBlock Text="{c:Binding BoolA and BoolB or BoolB}" />
修改一下界面
<StackPanel> <TextBlock> <Run Text="A=" /> <Run Text="{Binding BoolA}" /> </TextBlock> <TextBlock> <Run Text="B=" /> <Run Text="{Binding BoolB}" /> </TextBlock> <TextBlock Text="A and B" /> <TextBlock Text="{c:Binding BoolA and BoolB}" /> <TextBlock Text="A or B" /> <TextBlock Text="{c:Binding BoolA or BoolB}" /> </StackPanel>

其他可以寫的是表達式
<TextBox Text="{c:Binding A+B+C}"/> <TextBox Text="{c:Binding A-B-C}"/> <TextBox Text="{c:Binding A*(B+C)}"/> <TextBox Text="{c:Binding 2*A-B*0.5}"/> <TextBox Text="{c:Binding A/B, StringFormat={}{0:n2} --StringFormat is used}"/> {with string format} <TextBox Text="{c:Binding A%B}"/> <TextBox Text="{c:Binding '(A == 1) ? 10 : 20'}"/> {ternary operator}
判斷布爾
<CheckBox Content="!IsChecked" IsChecked="{c:Binding !IsChecked}"/> <TextBox Text="{c:Binding 'IsChecked and IsFull'}"/> {'and' is equvalent of '&&'} <TextBox Text="{c:Binding '!IsChecked or (A > B)'}"/> {'or' is equvalent of '||', but you can leave '||'} <TextBox Text="{c:Binding '(A == 1) and (B less= 5)'}"/> {'less=' is equvalent of '<='} <TextBox Text="{c:Binding (IsChecked || !IsFull)}"/>
因為在 xaml 不能使用 &&
||
<=
所以需要使用 and or ‘less=’ 替換
另外對於 :
之前需要添加空格,如下面代碼
<TextBox Text="{c:Binding '(A == 2)?IsChecked : IsFull}"/> <!-- right --> <TextBox Text="{c:Binding '(A == 2)?IsChecked :!IsFull}"/> <!-- right --> <TextBox Text="{c:Binding '(A == 2) ? IsChecked :4 + IsFull}"/> <!-- right -->
這些都是對的,但是下面的代碼是無法運行
<TextBox Text="{c:Binding '(A == 2)?IsChecked:IsFull}"/> <!-- wrong -->
可以綁定靜態的值,靜態的值的寫法 xmlNamespace:Class.StaticProperty.NestedProperty
命名空間下的類的靜態屬性的屬性
對於經常計算值這里也可以簡單使用,如 Math 里面的方法
<TextBox Text="{c:Binding Math.Sin(A*Math.PI/180), StringFormat={}{0:n5} }"/> <TextBox Text="{c:Binding A*Math.PI}" />
枚舉值也可以點命名空間的枚舉的值,可以用來判斷 xmlNamespace:EnumClass.Value
如在 Foo 枚舉里面有 A 這個值
<CheckBox IsChecked="{c:Binding 'Foo==local:Foo.A'}" />
經常會將 bool 轉換為 Visibility 這個庫也有簡單的方法
<Button Content="TargetButton" Visibility="{c:Binding HasPrivileges, FalseToVisibility=Collapsed}"/> or just <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges}"/> <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges, FalseToVisibility=Hidden}"/>
如果需要在樣式使用,需要通過 RelativeSource 找到方法
<Button Content="Button" Width="100"> <Button.Template> <ControlTemplate> <TextBox Width="{c:Binding Width+10, RelativeSource={RelativeSource TemplatedParent} }"/> </ControlTemplate> </Button.Template> </Button>