Xamarin.Forms 中的动态样式
样式不会响应属性更改,并在应用程序期间保持不变。 例如,将样式分配到视觉元素后,如果修改、删除其中一个 Setter 实例或添加新的 Setter 实例,则更改将不会应用于该视觉元素。 但应用程序可以通过使用动态资源在运行时动态响应样式更改。
DynamicResource
标记扩展与 StaticResource
标记扩展的相似之处在于,两者都使用字典键从 ResourceDictionary
中提取值。 但是,当 StaticResource
执行单个字典查找时,DynamicResource
会保持指向字典键的链接。 因此,如果替换与键关联的字典条目,则更改将应用于视觉对象元素。 这样,就可以在应用程序中进行运行时样式更改。
以下代码示例演示 XAML 页面中的动态样式:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesPage" Title="Dynamic" IconImageSource="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle"
TargetType="SearchBar"
BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle"
TargetType="SearchBar">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Placeholder="These SearchBar controls"
Style="{DynamicResource searchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>
SearchBar
实例使用 DynamicResource
标记扩展来引用名为 searchBarStyle
的、未在 XAML 中定义的 Style
。 不过,由于 SearchBar
实例的 Style
属性是使用 DynamicResource
设置的,因此缺少字典键不会导致引发异常。
相反,在代码隐藏文件中,构造函数会创建一个包含 searchBarStyle
键的 ResourceDictionary
条目,如以下代码示例所示:
public partial class DynamicStylesPage : ContentPage
{
bool originalStyle = true;
public DynamicStylesPage ()
{
InitializeComponent ();
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
}
void OnButtonClicked (object sender, EventArgs e)
{
if (originalStyle) {
Resources ["searchBarStyle"] = Resources ["greenSearchBarStyle"];
originalStyle = false;
} else {
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
originalStyle = true;
}
}
}
执行 OnButtonClicked
事件处理程序时,searchBarStyle
将在 blueSearchBarStyle
和 greenSearchBarStyle
之间切换。 这会导致如以下屏幕截图中所示的外观:
以下代码示例展示了 C# 中的等效页面:
public class DynamicStylesPageCS : ContentPage
{
bool originalStyle = true;
public DynamicStylesPageCS ()
{
...
var baseStyle = new Style (typeof(View)) {
...
};
var blueSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var greenSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
...
var searchBar1 = new SearchBar { Placeholder = "These SearchBar controls" };
searchBar1.SetDynamicResource (VisualElement.StyleProperty, "searchBarStyle");
...
Resources = new ResourceDictionary ();
Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
Content = new StackLayout {
Children = { searchBar1, searchBar2, searchBar3, searchBar4, button }
};
}
...
}
在 C# 中,SearchBar
实例使用 SetDynamicResource
方法来引用 searchBarStyle
。 OnButtonClicked
事件处理程序代码与 XAML 示例相同,执行时,searchBarStyle
将在 blueSearchBarStyle
和 greenSearchBarStyle
之间切换。
动态样式继承
无法使用 Style.BasedOn
属性从动态样式派生样式。 相反,Style
类包括 BaseResourceKey
属性,该属性可以设置为可动态更改其值的字典键。
以下代码示例演示 XAML 页面中的动态样式继承:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesInheritancePage" Title="Dynamic Inheritance" IconImageSource="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle" TargetType="SearchBar" BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle" TargetType="SearchBar">
...
</Style>
<Style x:Key="tealSearchBarStyle" TargetType="SearchBar" BaseResourceKey="searchBarStyle">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Text="These SearchBar controls" Style="{StaticResource tealSearchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>
SearchBar
实例使用 StaticResource
标记扩展来引用名为 tealSearchBarStyle
的 Style
。 此 Style
设置一些附加属性,并使用 BaseResourceKey
属性引用 searchBarStyle
。 不需要 DynamicResource
标记扩展,因为 tealSearchBarStyle
不会更改,但从其中派生的 Style
除外。 因此,tealSearchBarStyle
保留 searchBarStyle
的链接,并在基本样式更改时发生变化。
在代码隐藏文件中,构造函数创建一个包含 searchBarStyle
键的 ResourceDictionary
条目,如前面演示动态样式的示例所示。 执行 OnButtonClicked
事件处理程序时,searchBarStyle
将在 blueSearchBarStyle
和 greenSearchBarStyle
之间切换。 这会导致如以下屏幕截图中所示的外观:
以下代码示例展示了 C# 中的等效页面:
public class DynamicStylesInheritancePageCS : ContentPage
{
bool originalStyle = true;
public DynamicStylesInheritancePageCS ()
{
...
var baseStyle = new Style (typeof(View)) {
...
};
var blueSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var greenSearchBarStyle = new Style (typeof(SearchBar)) {
...
};
var tealSearchBarStyle = new Style (typeof(SearchBar)) {
BaseResourceKey = "searchBarStyle",
...
};
...
Resources = new ResourceDictionary ();
Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
Content = new StackLayout {
Children = {
new SearchBar { Text = "These SearchBar controls", Style = tealSearchBarStyle },
...
}
};
}
...
}
tealSearchBarStyle
直接分配到 SearchBar
实例的 Style
属性。 此 Style
设置一些附加属性,并使用 BaseResourceKey
属性引用 searchBarStyle
。 此处不需要 SetDynamicResource
方法,因为 tealSearchBarStyle
不会发生更改,但它派生自的 Style
除外。 因此,tealSearchBarStyle
保留 searchBarStyle
的链接,并在基本样式更改时发生变化。