在 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"]);
}
}
}
我有以下款式
<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"]);
}
}
}