c# - 在自定义 StackLayout(运行时)中所做的更改不会出现在视图中 (Xamarin.Forms)
问题描述
我已经实现了一个自定义布局,其主要特点是背景可以通过提供 2 种十六进制颜色来渐变。视图本身工作得很好,问题是程序运行时对这两种颜色所做的更改不会反映在应用程序中,自定义布局接收并更改新颜色并正确制作渐变,但它没有显示所做的更改。我认为问题在于我没有正确实现 INotifyPropertyChanged。
这是我的自定义视图的代码:
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace MyProject.Renderers
{
public class GradientLayout : StackLayout, INotifyPropertyChanged
{
public string ColorsList { get; set; }
public Color[] Colors
{
get
{
//colorsList have the following format: "HexCode1,HexCode2"
string[] hex = ColorsList.Split(',');
Color[] colors = new Color[hex.Length];
for (int i = 0; i < hex.Length; i++)
{
colors[i] = Color.FromHex(hex[i].Trim());
}
return colors;
}
}
//since this is a property that I am not trying to modify, I will not provide the rest of its code to make this as simple as possible.
public GradientColorStackMode Mode { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
仅此而已,如果您需要更多信息,我会在看到您的请求后立即提供,感谢大家的宝贵时间,希望您有美好的一天。
编辑:在这里,您在 myProject.ios 中有一个与背景渐变相关的类。
[assembly: ExportRenderer(typeof(GradientLayout), typeof(GradientLayoutRenderer))]
namespace MyProject.iOS.Renderers
{
public class GradientLayoutRenderer : VisualElementRenderer<StackLayout>
{
public override void Draw(CGRect rect)
{
base.Draw(rect);
GradientLayout layout = (GradientLayout)Element;
CGColor[] colors = new CGColor[layout.Colors.Length];
for (int i = 0, l = colors.Length; i < l; i++)
{
colors[i] = layout.Colors[i].ToCGColor();
}
var gradientLayer = new CAGradientLayer();
switch (layout.Mode)
{
default:
case GradientColorStackMode.ToRight:
gradientLayer.StartPoint = new CGPoint(0, 0.5);
gradientLayer.EndPoint = new CGPoint(1, 0.5);
break;
case GradientColorStackMode.ToLeft:
gradientLayer.StartPoint = new CGPoint(1, 0.5);
gradientLayer.EndPoint = new CGPoint(0, 0.5);
break;
case GradientColorStackMode.ToTop:
gradientLayer.StartPoint = new CGPoint(0.5, 0);
gradientLayer.EndPoint = new CGPoint(0.5, 1);
break;
case GradientColorStackMode.ToBottom:
gradientLayer.StartPoint = new CGPoint(0.5, 1);
gradientLayer.EndPoint = new CGPoint(0.5, 0);
break;
case GradientColorStackMode.ToTopLeft:
gradientLayer.StartPoint = new CGPoint(1, 0);
gradientLayer.EndPoint = new CGPoint(0, 1);
break;
case GradientColorStackMode.ToTopRight:
gradientLayer.StartPoint = new CGPoint(0, 1);
gradientLayer.EndPoint = new CGPoint(1, 0);
break;
case GradientColorStackMode.ToBottomLeft:
gradientLayer.StartPoint = new CGPoint(1, 1);
gradientLayer.EndPoint = new CGPoint(0, 0);
break;
case GradientColorStackMode.ToBottomRight:
gradientLayer.StartPoint = new CGPoint(0, 0);
gradientLayer.EndPoint = new CGPoint(1, 1);
break;
}
gradientLayer.Frame = rect;
gradientLayer.Colors = colors;
NativeView.Layer.InsertSublayer(gradientLayer, 0);
}
}
}
编辑:这里还有与渐变布局的声明和调用相关的 xaml 和 xaml.cs 代码。XAML.CS:
page.ColorsList = Items[0].StartColor+","+Items[0].EndColor;
page.Mode = MyProject.Renderers.GradientColorStackMode.ToBottomLeft;
XAML:
<renderers:GradientLayout
x:Name="page"
Opacity="0"
Mode="ToBottomLeft">
</renders:GradientLayout>
编辑:我尝试实现Juniorjiang的,在我完成之后我注意到1个变化,IOS类在我的xaml.cs类的构造函数之前执行,给我string[] hex = ColorsList.Split(',');
与我之前提到的相同的错误,因为ColorsList没有收到任何值,所以我为“colors”提供了 2 个默认值,并实现了一个条件来确保构造函数代码没有在 ColorsList 为空的情况下执行:
public GradientLayout()
{
if(colorsList != null)
{
//colorsList have the following format: "HexCode1,HexCode2"
string[] hex = ColorsList.Split(',');
colors = new Color[hex.Length];
for (int i = 0; i < hex.Length; i++)
{
colors[i] = Color.FromHex(hex[i].Trim());
}
// BindingContext = this;
}
else
{
colors = new Color[2];
colors[0] = Color.FromHex("#000000");
colors[1] = Color.FromHex("#000000");
}
}
之后执行代码没有给出任何错误,但它没有按预期工作,因为 IOS 类只调用类 1 时间(在构造视图时)。我也没有绑定任何东西,因为我不明白我应该做什么//BindingContext = this
解决方案
我认为您应该实现如下INotifyPropertyChanged
功能:
public class GradientLayout : StackLayout, INotifyPropertyChanged
{
private Color[] colors;
public string ColorsList { get; set; }
public Color[] Colors
{
set
{
if (colors != value)
{
colors = value;
OnPropertyChanged("Colors");
}
}
get
{
return colors;
}
}
public GradientLayout()
{
//colorsList have the following format: "HexCode1,HexCode2"
string[] hex = ColorsList.Split(',');
colors = new Color[hex.Length];
for (int i = 0; i < hex.Length; i++)
{
colors[i] = Color.FromHex(hex[i].Trim());
}
// BindingContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
并且更好地使用模型来绑定控件的属性。看看这个文档。
===================================更新=============== =====================
您可以使用 Bindable 属性来实现它。
创建一个CustomStackLayout:
public class CustomStackLayout : StackLayout
{
public static readonly BindableProperty ColorsProperty = BindableProperty.Create("Colors", typeof(string), typeof(CustomStackLayout), "Default Value");
public string Colors
{
get { return (string)GetValue(ColorsProperty); }
set { SetValue(ColorsProperty, value); }
}
}
在Xaml中,添加 Tap 方法来更改属性CustomStackLayout
:
<local:CustomStackLayout HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
BackgroundColor="Gray">
<local:CustomStackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
</local:CustomStackLayout.GestureRecognizers>
</local:CustomStackLayout>
TapGestureRecognizer_Tapped
方法:
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
Console.WriteLine("--TapGestureRecognizer_Tapped--");
var customStacklayout = sender as CustomStackLayout;
customStacklayout.Colors = "new value";
}
因此,在iOS Renderer文件中,有一个OnElementPropertyChanged
方法可以监听哪些属性发生了变化。在这里您还可以更新 UI 。
[assembly: ExportRenderer(typeof(CustomStackLayout),typeof(CustomStackLayoutRenderer))]
namespace AppFrameRenderer.iOS
{
public class CustomStackLayoutRenderer : ViewRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var customStack = sender as CustomStackLayout;
Console.WriteLine("----" + customStack.Colors);
if (customStack.Colors == "Default Value")
{
//--
}
else
{
BackgroundColor = UIColor.Red;
}
}
}
}
效果如下:
推荐阅读
- memory-management - 在 vm_fault() 中预取,Linux 驱动程序
- c# - 改变重力方向
- python - 在 keras 自定义损失函数中获取训练数据形状
- csv - 将 CSV 数据复制到包含可为空列的 Azure SQL 数据库
- python - 汇总列列表
- python - 绘制平滑 matplotlib 和 seaborn
- sql-server - 在大量数据库调用之间进行选择,或通过在单个搜索中聚合信息来减少调用次数
- azure - 使用 Azure 提供程序的 Terraform “AuthorizationFailed”
- flutter - Flutter 中的 TextFormField 验证
- c++ - 无法将 const char 字符串传递给模板类