Avalonia學(xué)習(xí)
2023.03.30 Avalonia學(xué)習(xí)
原文地址:https://www.firstsaofan.top/archives/20230330avalonia-xue-xi
數(shù)據(jù)綁定:變化通知
中文地址:變化通知 - Avalonia UI (gitbook.io)
英文地址:Change Notifications - Avalonia UI
建議對照著看因為有些單詞翻譯過來變味了,需要看原單詞比較容易理解
格式字符串
你可以為綁定設(shè)置格式字符串,從而影響在UI上如何展現(xiàn)值:
?<!-- 選項 1: 使用花括號對格式字符串進行轉(zhuǎn)義 -->
?<TextBlock?Text="{Binding FloatValue, StringFormat={}{0:0.0}}"?/>
?
?<!-- 選項 2: 使用反斜線對格式字符串進行轉(zhuǎn)義 -->
?<TextBlock?Text="{Binding FloatValue, StringFormat=\{0:0.0\}}"?/>
?
?<!-- 選項 3: 如果格式字符串并非以{0}開始,則不需要轉(zhuǎn)義 -->
?<!-- 注意:如果在格式字符串中存在空格,則需要用單引號''包裹起來 -->
?<TextBlock?Text="{Binding Animals.Count, StringFormat='I have {0} animals.'}"?/>
?<!-- 注意: 如果格式字符串以{0}開始則需要轉(zhuǎn)義,例如:-->
?<TextBlock?Text="{Binding Animals.Count, StringFormat='{}{0} animals live in the farm.'}"?/>
當(dāng)StringFormat
屬性存在時,綁定的值將會由StringFormatValueConverter
利用指定的格式字符串進行轉(zhuǎn)換。
與WPF不同,你需要將格式字符串用花括號包裹起來并以0:
開始({0:TheStringFormat}
)。如果格式字符串中花括號出現(xiàn)在開始,那么即使用單引號包裹起來,也需要進行轉(zhuǎn)義。可以在前面加{}
,也可以使用反斜線\{...\}
:
WPF:
?<TextBlock?Text="{Binding FloatValue, StringFormat=0.0}"?/>
Avalonia:
?<TextBlock?Text="{Binding FloatValue, StringFormat={}{0:0.0}}"?/>
?
?<TextBlock?Text="{Binding FloatValue, StringFormat=\{0:0.0\}}"?/>
?
?<TextBlock?Text="{Binding FloatValue, StringFormat='{}{0:0.0}'}"?/>
格式字符串詳情請閱讀微軟文檔
編譯綁定
在XAML中定義的綁定是通過反射來實現(xiàn)尋找和訪問視圖模型中的屬性的。在Avalonia中你還可以使用編譯綁定。這樣有一些好處:
如果你使用編譯綁定但沒有找到你想要綁定的屬性,會得到編譯期錯誤,得到更好的調(diào)試體驗。
眾所周知,反射很慢(可以閱讀codeproject.com的這篇文章)。使用編譯綁定可以提升應(yīng)用的性能。
開啟或禁用編譯綁定
編譯綁定默認不開啟。想要開啟編譯綁定,你需要先通過DataType
定義想要綁定的目標(biāo)的類型。在DataTemplates數(shù)據(jù)模板
中有DataType
屬性,在其他元素中可以使用x:DataType
。通常你會在根節(jié)點設(shè)置x:DataType
,例如Window
和UserControl
。從Avalonia0.10.12
開始,你還可以在Binding
中直接指定DataType
。
現(xiàn)在你可以開啟或禁用編譯綁定,方法是設(shè)置x:CompileBindings="[True|False]"
。所有的子節(jié)點都會繼承這一屬性,需要的時候也可以為全局開啟,為特定的子節(jié)點禁用。
?<!--設(shè)置DataType并開啟全局綁定 -->
?<UserControl?xmlns="https://github.com/avaloniaui"
??? ? ? ? ? ??xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
??? ? ? ? ? ??xmlns:vm="using:MyApp.ViewModels"
??? ? ? ? ? ??x:DataType="vm:MyViewModel"
??? ? ? ? ? ??x:CompileBindings="True">
??? ?<StackPanel>
??? ? ? ?<TextBlock?Text="Last name:"?/>
??? ? ? ?<TextBox?Text="{Binding LastName}"?/>
??? ? ? ?<TextBlock?Text="Given name:"?/>
??? ? ? ?<TextBox?Text="{Binding GivenName}"?/>
??? ? ? ?<TextBlock?Text="E-Mail:"?/>
??? ? ? ?<!-- 在綁定標(biāo)記中設(shè)置DataType -->
??? ? ? ?<TextBox?Text="{Binding MailAddress, DataType={x:Type vm:MyViewModel}}"?/>
?
??? ? ? ?<!-- 我們無法在編譯綁定中綁定到方法,所以對于按鈕需要做出讓步 -->
??? ? ? ?<Button?x:CompileBindings="False"
??? ? ? ? ? ? ? ?Content="Send an E-Mail"
??? ? ? ? ? ? ? ?Command="{Binding SendEmailCommand}"?/>
??? ?</StackPanel>
?</UserControl>
CompiledBinding標(biāo)記
如果你不想對所有子節(jié)點開啟編譯綁定,也可以使用CompiledBinding
標(biāo)記。你仍然需要設(shè)置DataType
,但可以省略x:CompileBindings="True"
。
?<!-- 設(shè)置 DataType -->
?<UserControl?xmlns="https://github.com/avaloniaui"
??? ? ? ? ? ??xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
??? ? ? ? ? ??xmlns:vm="using:MyApp.ViewModels"
??? ? ? ? ? ??x:DataType="vm:MyViewModel">
??? ?<StackPanel>
??? ? ? ?<TextBlock?Text="Last name:"?/>
??? ? ? ?<!-- 使用CompiledBinding標(biāo)記進行綁定 -->
??? ? ? ?<TextBox?Text="{CompiledBinding LastName}"?/>
??? ? ? ?<TextBlock?Text="Given name:"?/>
??? ? ? ?<TextBox?Text="{CompiledBinding GivenName}"?/>
??? ? ? ?<TextBlock?Text="E-Mail:"?/>
??? ? ? ?<TextBox?Text="{CompiledBinding MailAddress}"?/>
?
??? ? ? ?<!-- 我們無法在編譯綁定中綁定到方法,所以使用正常的綁定(Binding) -->
??? ? ? ?<Button?Content="Send an E-Mail"
??? ? ? ? ? ? ? ?Command="{Binding SendEmailCommand}"?/>
??? ?</StackPanel>
?</UserControl>
ReflectionBinding標(biāo)記
如果你在根節(jié)點開啟了編譯綁定(通過x:CompileBindings="True"
),但對于特定的位置并不想用編譯綁定,或者遇到了編譯綁定的局限,你可以使用ReflectionBinding
標(biāo)記。
?<!-- 設(shè)置 DataType -->
?<UserControl?xmlns="https://github.com/avaloniaui"
??? ? ? ? ? ??xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
??? ? ? ? ? ??xmlns:vm="using:MyApp.ViewModels"
??? ? ? ? ? ??x:DataType="vm:MyViewModel"
??? ? ? ? ? ??x:CompileBindings="True">
??? ?<StackPanel>
??? ? ? ?<TextBlock?Text="Last name:"?/>
??? ? ? ?<TextBox?Text="{Binding LastName}"?/>
??? ? ? ?<TextBlock?Text="Given name:"?/>
??? ? ? ?<TextBox?Text="{Binding GivenName}"?/>
??? ? ? ?<TextBlock?Text="E-Mail:"?/>
??? ? ? ?<TextBox?Text="{Binding MailAddress}"?/>
?
??? ? ? ?<!-- 我們無法在編譯綁定中綁定到方法,所以使用ReflectionBinding -->
??? ? ? ?<Button?Content="Send an E-Mail"
??? ? ? ? ? ? ? ?Command="{ReflectionBinding SendEmailCommand}"?/>
??? ?</StackPanel>
?</UserControl>
已知限制
編譯綁定有一些已知的限制:
編譯綁定無法綁定到通過名字指定的元素
編譯綁定無法在樣式中通過RelativeResource綁定到TemplatedParent(例如:{Binding Width, RelativeSource={RelativeSource TemplatedParent}})
如果你遇到了上述的限制,你需要禁用編譯綁定或使用ReflectionBinding
。
總結(jié):開啟,可以檢查自己綁定的屬性或者對象是否正確,并能提升性能。但是需要注意特殊場景被限制
Avalonia對漢字的顯示不夠友好
以下樣式是對全局的textbox的漢字進行設(shè)置可以正常顯示,其他的控件也可參照此例
?<Window.Styles>
????<Style?Selector="TextBox"?>
??? ? ?<Setter?Property="FontFamily"?Value="宋體,Simsun,微軟雅黑,Microsoft YaHei,蘋方-簡,宋體-簡">
??? ? ?</Setter>
????</Style>
?</Window.Styles>
以下是正常運行的結(jié)果:

參考博客:https://hedaozi.com/technology/font-in-avalonia/
與控件綁定
綁定到已命名控件
如果要綁定到另一個已命名控件的屬性,可以使用以#
字符為前綴的控件名稱。
?<TextBox?Name="other">
?
?<!-- 綁定到命名為“other”控件的Text屬性 -->
?
?<TextBlock?Text="{Binding #other.Text}"/>
這相當(dāng)于WPF和UWP開發(fā)者熟悉的長格式綁定:
?<TextBox?Name="other">
?
?<TextBlock?Text="{Binding Text, ElementName=other}"/>
這兩種語法Avalonia均支持,但縮寫#
語法顯得不那么冗長。
綁定到父控件或者父控件的父控件
您可以使用$parent
符號綁定到目標(biāo)在邏輯上的父級:
?<Border?Tag="Hello World!">
?
???<TextBlock?Text="{Binding $parent.Tag}"/>
?
?</Border>
也可以通過在$parent
符號添加索引器綁定到父控件的父控件:
?<Border?Tag="Hello World!">
???<Border>
??? ?<TextBlock?Text="{Binding $parent[1].Tag}"/>
???</Border>
?</Border>
索引器從0開始,因此$parent[0]
等同于$parent
。
還可以按類型綁定到祖先:
?<Border?Tag="Hello World!">
???<Decorator>
???<TextBlock?Text="{Binding $parent[Border].Tag}"/>
???</Decorator>
?</Border>
最后,您可以組合索引器和類型:
?<Border?Tag="Hello World!">
???<Border>
???<Decorator>
???<TextBlock?Text="{Binding $parent[Border;1].Tag}"/>
???</Decorator>
???</Border>
?</Border>
如果需要在祖先類型中包含XAML命名空間,一般使用:
字符:
?<local:MyControl?Tag="Hello World!">
???<Decorator>
???? ?<TextBlock?Text="{Binding $parent[local:MyControl].Tag}"/>
???</Decorator>
?</local:MyControl>