在 WinPHone 8.1 上使用 Xamarin.Forms 根据触发器更改样式

Changing style based on trigger with Xamarin.Forms on WinPHone 8.1

我有以下款式

<Style x:Key="GreenButtonStyle" BasedOn="{StaticResource MyButtonBaseStyle}" TargetType="Button">
    <Style.Triggers>
        <Trigger TargetType="Button" Property="IsEnabled" Value="False">
            <Setter Property="BackgroundColor" Value="Silver" />
            <Setter Property="TextColor" Value="Black" />
        </Trigger>
        <Trigger TargetType="Button" Property="IsEnabled" Value="True">
            <Setter Property="BackgroundColor" Value="Green" />
            <Setter Property="TextColor" Value="Orange" />
        </Trigger>
    </Style.Triggers>
</Style>

我在下面的视图中使用了它。

<Button x:Name="ConfirmButton" 
    Text="Confirm" 
    Style="{StaticResource GreenButtonStyle}" 
    IsEnabled="{Binding Source={x:Reference Some}, Path=ConfirmEnabled}"
    /> 
<Button x:Name="ToggleButton"
    Text="Toggle" 
    Clicked="Toggle_Clicked"
    />

后面有代码(只是片段)

public partial class SomeView : ContentPage, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool _confirmEnabled = false;
    public bool ConfirmEnabled
    {
        get { return _confirmEnabled; }
    }

    private void Toggle_Clicked(object sender, EventArgs e)
    {
        _confirmEnabled = !_confirmEnabled;
        PropertyChanged(this, new PropertyChangedEventArgs(nameof(ConfirmEnabled)));
    }
}

当视图开始播放时,按钮处于非活动状态时一切正常。当我单击切换按钮时,字体颜色按预期更改为橙色,但背景颜色没有更改为绿色。

如果我点击开关两次(禁用然后启用),字体为橙色,背景最终为绿色。

有人知道为什么第一次将 ConfirmEnabled 更改为 true 时背景颜色没有更改吗?

我建议您对应用程序设计使用 MVVM 方法。创建一个名为 BaseViewModel.cs 的 class 和一个名为 SomeViewModel.cs 的 class,然后这样写:

BaseViewModel.cs,每个视图模型都应该继承。它允许您使用 PropertyChanged 事件:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

SomeViewModel.cs。现在每次更改 ConfirmEnabled 的值时,视图都可以在设置绑定后自动检测更改:

public class SomeViewModel : BaseViewModel
{
    private bool _confirmEnabled = false;

    public bool ConfirmEnabled
    {
        get { return _confirmEnabled; }
        set 
        { 
            _confirmEnabled = value;
            OnPropertyChanged(nameof(ConfirmEnabled));
        }
    }
}

现在,对于您的页面 SomeView.cs:

public partial class SomeView : ContentPage, INotifyPropertyChanged
{
    SomeViewModel _viewModel;

    public SomeView()
    {
        InitializeComponent();
        _viewModel = new SomeViewModel();
        BindingContext = _viewModel;
    }

    private void Toggle_Clicked(object sender, EventArgs e)
    {
        _viewModel.ConfirmEnabled = !_viewModel.ConfirmEnabled;
    }
}

以及您的按钮代码:

    <Button x:Name="ConfirmButton" 
        Text="Confirm" 
        Style="{StaticResource GreenButtonStyle}" 
        IsEnabled="{Binding ConfirmEnabled}"
        /> 
    <Button x:Name="ToggleButton"
        Text="Toggle" 
        Clicked="Toggle_Clicked"
        />

以实现我自己的按钮控件结束,它基本上是两个按钮在彼此之上,然后根据它是启用还是禁用我隐藏或显示另一个。

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyProject.Views._Controls.MyButton">

    <Grid>
        <Button x:Name="WhenEnabledButton"
                Clicked="WhenEnabledButton_Clicked"
                Text="WhenEnabled"></Button>
        <Button x:Name="WhenDisabledButton"
                Text="WhenDisabled"></Button>
        <Label x:Name="DisabledButtonCoveringLabel" BackgroundColor="Transparent"></Label>
    </Grid>
</ContentView>

以及背后的代码

namespace MyProject.Views._Controls
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MyButton : ContentView
    {
        #region Property Bindings
        public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(MyButton),
            null, propertyChanged: (bo, o, n) => ((MyButton)bo).OnCommandChanged());

        public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object),
            typeof(MyButton), null,
        propertyChanged: (bindable, oldvalue, newvalue) => ((MyButton)bindable).CommandCanExecuteChanged(bindable, EventArgs.Empty));

        public static readonly new BindableProperty IsEnabledProperty =
            BindableProperty.Create(
                propertyName: "IsEnabled",
                returnType: typeof(Boolean),
                declaringType: typeof(MyButton),
                defaultValue: false,
                defaultBindingMode: BindingMode.OneWay,
                propertyChanged: IsEnabledChanged);

        private static void IsEnabledChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (MyButton)bindable;
            bool enabled = (bool)newValue;
            control.WhenEnabledButton.IsVisible = enabled;
            control.WhenDisabledButton.IsVisible = !enabled;

            if (Device.RuntimePlatform == Device.WinPhone || Device.RuntimePlatform == Device.WinRT)
            {
                control.DisabledButtonCoveringLabel.IsVisible = !enabled;
            }
        }

        public static readonly BindableProperty TextProperty =
            BindableProperty.Create(
                propertyName: "Text",
                returnType: typeof(string),
                declaringType: typeof(MyButton),
                defaultValue: string.Empty,
                defaultBindingMode: BindingMode.OneWay,
                propertyChanged: TextChanged);

        private static void TextChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (MyButton)bindable;
            control.WhenEnabledButton.Text = (string)newValue;
            control.WhenDisabledButton.Text = (string)newValue;
        }

        public static readonly BindableProperty EnabledStyleProperty =
            BindableProperty.Create(
                propertyName: "EnabledStyle",
                returnType: typeof(Style),
                declaringType: typeof(MyButton),
                defaultBindingMode: BindingMode.OneWay,
                propertyChanged: EnabledStyleChanged);

        private static void EnabledStyleChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (MyButton)bindable;
            control.WhenEnabledButton.Style = (Style)newValue;
        }

        public static readonly BindableProperty DisabledStyleProperty =
            BindableProperty.Create(
                propertyName: "DisabledStyle",
                returnType: typeof(Style),
                declaringType: typeof(MyButton),
                defaultBindingMode: BindingMode.OneWay,
                propertyChanged: DisabledStyleChanged);

        private static void DisabledStyleChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (MyButton)bindable;
            control.WhenDisabledButton.Style = (Style)newValue;
        }
        #endregion


        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public string Text
        {
            get
            {
                return this.GetValue<string>(TextProperty);
            }

            set
            {
                this.SetValue(TextProperty, value);
            }
        }

        public new bool IsEnabled
        {
            get
            {
                return this.GetValue<bool>(IsEnabledProperty);
            }

            set
            {
                this.SetValue(IsEnabledProperty, value);
            }
        }

        #region Click event

        public delegate void ClickedHandler(object sender, EventArgs e);
        public event ClickedHandler Clicked;

        private void WhenEnabledButton_Clicked(object sender, EventArgs e)
        {
            if (Clicked != null)
                this.Clicked.Invoke(sender, e);
            else
                this.Command.Execute(this.CommandParameter);
        }

        void CommandCanExecuteChanged(object sender, EventArgs eventArgs)
        {
            ICommand cmd = Command;
            if (cmd != null)
                IsEnabled = cmd.CanExecute(CommandParameter);
        }

        void OnCommandChanged()
        {
            if (Command != null)
            {
                Command.CanExecuteChanged += CommandCanExecuteChanged;
                CommandCanExecuteChanged(this, EventArgs.Empty);
            }
            else
                IsEnabled = true;
        }

        #endregion

        public MyButton()
        {
            InitializeComponent();
            if (Device.RuntimePlatform == Device.Android)
            {
                DisabledButtonCoveringLabel.IsVisible = false;
                WhenDisabledButton.IsEnabled = false;
            }
            else if (Device.RuntimePlatform == Device.WinPhone || Device.RuntimePlatform == Device.WinRT)
            {
                DisabledButtonCoveringLabel.IsVisible = true;
                WhenDisabledButton.IsEnabled = true;
            }

            this.SetValue(EnabledStyleProperty, Application.Current.Resources["GreenEnabledButtonStyle"]);
            this.SetValue(DisabledStyleProperty, Application.Current.Resources["GreenDisabledButtonStyle"]);
        }
    }
}