问题描述
我创建了一个自定义的 Frame
和 View
。我将 Frame
中的 View
和 Page
与 Style
资源相结合,如下所示。
主页
<ContentPage.Resources>
<Style x:Key="Style" targettype="local:MyFrame">
<Setter Property="HorizontalOptions" Value="FillAndExpand" />
<Setter Property="BackgroundColor" Value="LimeGreen" />
</Style>
</ContentPage.Resources>
<local:MyView>
<local:MyView.Views>
<local:MyFrame Style="{StaticResource Style}"
HorizontalOptions="FillAndExpand"
Title="Number one" />
</local:MyView.Views>
</local:MyView>
我的视图
public class MyView : ContentView
{
private readonly StackLayout _layout;
public ObservableCollection<View> Views { get; set; }
public MyView()
{
Views = new ObservableCollection<View>();
Views.CollectionChanged += OnViewsCollectionChanged;
_layout = new StackLayout();
Content = _layout;
}
private void OnViewsCollectionChanged(object sender,NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
foreach (View view in e.OldItems)
_layout.Children.Remove(view);
if (e.NewItems != null)
foreach (View view in e.NewItems)
_layout.Children.Add(view);
}
}
我的框架
public class MyFrame : Frame
{
private readonly Label _title;
public string Title { set => _title.Text = value; }
public MyFrame()
{
BackgroundColor = Color.LightPink;
_title = new Label
{
TextColor = Color.Black,FontSize = 16,};
Content = _title;
}
}
我期望在 MyFrame
背景上使用 LimeGreen 颜色,因为我在 MyFrame.Style
中设置了 MainPage
,但实际结果是 LightPink。
我猜在 BackgroundColor
构造函数中设置 MyFrame
并不是要设置默认值。那么如何为 BackgroundColor
设置默认 MyFrame
?
我将实际项目简化为可复制的小型项目。这是Github
更新
注释掉 BackgroundColor = Color.LightPink;
代码,结果是 LimeGreen 颜色... 那么我如何设置默认的 MyFrame.BackgroundColor
?
解决方法
我可以重现您的问题,我可以建议对您的代码进行以下修改,以便能够为您的 MyFrame 视图设置默认背景颜色:
对 MyFrame 的修改
为了解决您的问题,我将 MyFrame 修改为在 Xaml 中定义:
MyFrameXaml.xaml
<?xml version="1.0" encoding="UTF-8"?>
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StyleDoesNotApply.MyFrameXAML"
BackgroundColor="{Binding MyBackgroundColor}">
<Label x:Name="title"
TextColor="Black"
FontSize="16"/>
</Frame>
然后,在后面的代码中定义 MyBackgroundColor 属性如下:
MyFrameXaml.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace StyleDoesNotApply
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyFrameXAML : Frame
{
public string Title { set => title.Text = value; }
public static readonly BindableProperty MyBackgroundColorProperty =
BindableProperty.Create(nameof(MyBackgroundColor),typeof(Color),typeof(MyFrame),Color.LightPink);
public Color MyBackgroundColor
{
get => (Color)GetValue(MyBackgroundColorProperty);
set => SetValue(MyBackgroundColorProperty,value);
}
public MyFrameXAML()
{
BindingContext = this;
InitializeComponent();
}
}
}
使用新视图
<ContentPage.Resources>
<Style x:Key="Style" TargetType="local:MyFrameXAML">
<Setter Property="HorizontalOptions" Value="StartAndExpand" />
<Setter Property="MyBackgroundColor" Value="LimeGreen" />
</Style>
</ContentPage.Resources>
<StackLayout>
<Label Text="Style does apply!"
FontSize="Title"
TextColor="Black"/>
<local:MyView>
<local:MyView.Views>
<local:MyFrameXAML Style="{StaticResource Style}"
HorizontalOptions="FillAndExpand"
Title="Number one" />
</local:MyView.Views>
</local:MyView>
</StackLayout>
更新
可重用代码
public static BindableProperty Override(
this BindableProperty bindableProperty,string propertyName = null,Type returnType = null,Type declaringType = null,object defaultValue = null,BindingMode defaultBindingMode = BindingMode.OneWay,BindableProperty.ValidateValueDelegate validateValue = null,BindableProperty.BindingPropertyChangedDelegate propertyChanged = null,BindableProperty.BindingPropertyChangingDelegate propertyChanging = null,BindableProperty.CoerceValueDelegate coerceValue = null,BindableProperty.CreateDefaultValueDelegate defaultValueCreator = null)
{
if (string.IsNullOrEmpty(propertyName))
propertyName = bindableProperty.PropertyName;
if (returnType == null)
returnType = bindableProperty.ReturnType;
if (declaringType == null)
declaringType = bindableProperty.DeclaringType;
if (defaultValue == null)
defaultValue = bindableProperty.DefaultValue;
if (propertyChanged == null)
propertyChanged = (bindable,oldValue,newValue) =>
{
var property = bindableProperty.DeclaringType.GetProperty(bindableProperty.PropertyName);
property.SetValue(bindable,newValue);
};
return BindableProperty.Create(propertyName,returnType,declaringType,defaultValue,defaultBindingMode,validateValue,propertyChanged,propertyChanging,coerceValue,defaultValueCreator);
}
public class MyFrame : Frame
{
// override existing BindableProperty
public static new readonly BindableProperty BackgroundColorProperty = VisualElement.BackgroundColorProperty.Override();
private readonly Label _title;
public string Title { set => _title.Text = value; }
public MyFrame()
{
BackgroundColor = Color.LightPink;
_title = new Label
{
TextColor = Color.Black,FontSize = 16,};
Content = _title;
}
}