Изменения, сделанные в пользовательском StackLayout (при запуске), не отображаются в представлении (Xamarin.Forms) - PullRequest
0 голосов
/ 06 апреля 2020

Я реализовал пользовательский макет, основная характеристика которого c заключается в том, что фон может быть градиентом, давая 2 шестнадцатеричных цвета. Сам вид прекрасно работает, проблема в том, что изменения, сделанные в этих двух цветах во время работы программы, не отражают себя в приложении, пользовательский макет получает и изменяет оба новых цвета и правильно создает градиент, но это не так показать сделанные изменения. Я предполагаю, что проблема в том, что я неправильно реализовал I 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);
        }
    }
}

EDIT: Также вот код 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>

РЕДАКТИРОВАТЬ: Я пытался реализовать Junior Jiang´s, после того, как я это сделал, я заметил 1 изменение, класс IOS выполнялся до конструктора моего класса xaml.cs, давая мне в string[] hex = ColorsList.Split(','); ту же ошибку, что я упоминал ранее, потому что ColorsList не получил никакого значения, поэтому я присвоил 2 значения по умолчанию для «colors» и реализовал условие, чтобы убедиться, что код конструктора не был выполнен с 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

1 Ответ

1 голос
/ 07 апреля 2020

Я думаю, вы должны реализовать функцию 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));
    }
}

И лучше использовать Модель для привязки свойств для элемента управления. Посмотрите на это сделать c.

================================= Обновить =========================================

Вы можете использовать Bindable Property для реализации этого.

Создание 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, который может прослушивать, что изменилось надлежащим образом. Здесь вы также можете обновить пользовательский интерфейс.

[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;
            }
        }

    }
}

Эффект следующим образом:

enter image description here

...