【问题标题】:C#, Xamarin Forms: No Custom TextChangedEvent Raised on initializationC#,Xamarin 表单:初始化时未引发自定义 TextChangedEvent
【发布时间】:2021-12-08 08:07:13
【问题描述】:

我正在创建一个 Xamarin.Forms MVVM 应用程序(仅使用 Android),只要它们的文本属性具有特定值,就需要将某些按钮标为红色。 (目的:提醒用户按下按钮并选择一个值,这将改变按钮文本属性,从而去除红色轮廓)

为此,我创建了以下文档:

自定义按钮 CButton 扩展默认 Button

    public class CButton : Button
    {
        // this Hides the Default .Text-Property
        public string Text 
        {
            get => base.Text;
            set
            {
                base.Text = value;
                TextChangedEvent(this, new EventArgs());
            }

        }
        // The Raised Event
        protected virtual void TextChangedEvent(object sender, EventArgs e)
        {
            EventHandler<EventArgs> handler = TextChanged;
            handler(sender, e);
        }
        public event EventHandler<EventArgs> TextChanged;
    }

自定义行为使用了引发的TextChangedEvent

    public class ButtonValBehavior : Behavior<CButton>
    {
        protected override void OnAttachedTo(CButton bindable)
        {
            bindable.TextChanged += HandleTextChanged;
            base.OnAttachedTo(bindable);
        }
        void HandleTextChanged(object sender, EventArgs e)
        {
            string forbidden = "hh:mm|dd.mm.yyyy";
            if (forbidden.Contains((sender as CButton).Text.ToLower()))
            {
                //Do when Button Text = "hh:mm" || "dd.mm.yyyy"
                (sender as CButton).BorderColor = Color.Gray;
            }
            else
            {
                //Do whenever Button.Text is any other value
                (sender as CButton).BorderColor = Color.FromHex("#d10f32");
            }
        }
        protected override void OnDetachingFrom(CButton bindable)
        {
            bindable.TextChanged -= HandleTextChanged;
            base.OnDetachingFrom(bindable);
        }
    }

ViewModel 的相关部分如下所示:

    public class VM_DIVI : VM_Base
    {
        public VM_DIVI(O_BasisProtokoll base)
        {
            Base = base;
        }

        private O_BasisProtokoll _base = null;
        public O_BasisProtokoll Base
        {
            get => _base;
            set
            {
                _base = value;
                OnPropertyChanged();
            }
        }

        Command _datePopCommand;
        public Command DatePopCommand
        {
            get
            {
                return _datePopCommand ?? (_datePopCommand = new Command(param => ExecuteDatePopCommand(param)));
            }
        }
        void ExecuteDatePopCommand(object param)
        {
            //launch popup
            var p = new PP_DatePicker(param);
            PopupNavigation.Instance.PushAsync(p);
        }
    }

.xmal 看起来如下(b 是命名空间的xmlns):

    <b:CButton x:Name="BTN_ED_Datum"
               Text="{Binding Base.ED_datum, Mode=TwoWay}" 
               Grid.Column="1"
               Command="{Binding DatePopCommand}" 
               CommandParameter="{x:Reference BTN_ED_Datum}">
        <b:CButton.Behaviors>
            <b:ButtonValBehavior/>
        </b:CButton.Behaviors>
    </b:CButton>

只要输入是由用户交互引起的,此解决方案就可以正常工作。但是,在页面初始化期间分配值时,不会创建红色轮廓,实际上不会引发 TextChangedEvent。通过使用断点,我注意到在初始化期间,CButtonText 属性从未设置过,尽管它实际上会在视图中。

尽管摆弄我的解决方案,但我无法在初始化时完成这项工作。我试图通过在构造函数中默认列出每个按钮来解决这个问题,但是这会将每个按钮都勾勒成红色,即使它们的文本值不需要它们也是如此。

我怎样才能实现我最初的目标?

非常感谢!

【问题讨论】:

  • 在继承的类中定义同名的新属性通常不是一个好主意,尤其是当您尝试隐藏的属性与其他属性交互时。基类 Button 上的 TextProperty 可绑定属性不知道您的新 Text 属性,这可能是您行为不一致的根源。我建议在您的子类中使用 PropertyChanged 事件并检查 e.PropertyName == nameof(Text)
  • 正如 Andrew 所说,尝试将属性 Text 修改为另一个名称,例如 MyText,并在 xaml 中使用新属性。

标签: button events xamarin.forms data-binding behavior


【解决方案1】:

已经有一段时间了,但如果我没记错的话,我最终做的是:

  • 将我的自定义按钮的新 Text-Property 更改为 CText
  • 确保我为任何元素激活了Mode=TwoWay,默认情况下没有启用它。 (在 msdn 上查找绑定模式以获取更多信息)
  • 使CText 成为CButton 的可绑定属性

我的自定义按钮现在如下所示:

using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;

namespace EORG_Anton.Model
{
    public class CButton : Button
    {
        public static readonly BindableProperty CTextProperty = 
            BindableProperty.Create(nameof(CText), 
            typeof(string), 
            typeof(CButton), 
            default(string), 
            BindingMode.TwoWay,
            propertyChanged: OnTextChanged);
        private static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (CButton)bindable;
            var value = (string)newValue;
            control.CText = value;
        }
        public string CText
        {
            get => base.Text;
            set
            {
                base.Text = value;
                TextChangedEvent(this, new EventArgs());
            }

        }
        protected virtual void TextChangedEvent(object sender, EventArgs e)
        {
            EventHandler<EventArgs> handler = TextChanged;
            handler(sender, e);
        }
        public event EventHandler<EventArgs> TextChanged;
    }
}

【讨论】:

    猜你喜欢
    • 2021-03-24
    • 2016-08-16
    • 2021-07-07
    • 1970-01-01
    • 2014-03-18
    • 2019-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多