我有一个视图模型:
public partial class ItemViewModel : ObservableObject
{
[ObservableProperty]
double _quantity;
[ObservableProperty]
double _price;
[ObservableProperty]
string _selectedProperty;
[RelayCommand]
void SetSelectedProperty(string selectedProperty)
=> SelectedProperty = selectedProperty;
}
自定义控件
Numpad
:
public partial class Numpad : ContentView
{
double? _value;
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
propertyName: nameof(Text),
returnType: typeof(string),
defaultValue: "0",
defaultBindingMode: BindingMode.TwoWay,
declaringType: typeof(Numpad),
propertyChanged: (bindable, oldValue, newValue) =>
{
var @this = (Numpad)bindable;
((Command)@this.UpCommand).ChangeCanExecute();
((Command)@this.DownCommand).ChangeCanExecute();
});
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public ICommand UpCommand { get; }
public ICommand DownCommand { get; }
public Numpad()
{
UpCommand = new Command(
execute: () =>
{
Text = $"{_value + 1}";
},
canExecute: () =>
{
if (double.TryParse(Text, out double x))
{
_value = x;
return true;
}
_value = null;
return false;
}
);
DownCommand = new Command(
execute: () =>
{
Text = $"{_value - 1}";
},
canExecute: () =>
{
if (double.TryParse(Text, out double x))
{
_value = x;
return _value > 0;
}
_value = null;
return false;
}
);
InitializeComponent();
}
}
及其 XAML:
<ContentView
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:loc="clr-namespace:MyProject.Views"
x:Class="MyProject.Views.Numpad"
x:Name="This">
<VerticalStackLayout BindingContext="{Reference This}">
<Button
Text="Up"
Command="{Binding UpCommand}" />
<Button
Text="Down"
Command="{Binding DownCommand}" />
</VerticalStackLayout>
</ContentView>
两者都在
MainPage
中使用,如下所示:
public MainPage()
{
InitializeComponent();
BindingContext = new ItemViewModel { Quantity = 3, Price = 5 };
}
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:loc="clr-namespace:MyProject.Views"
xmlns:vm="clr-namespace:MyProject.ViewModels"
x:Class="MyProject.MainPage"
x:DataType="vm:ItemViewModel"
Title="Main Page">
<VerticalStackLayout>
<Button
Text="{Binding Quantity}"
Command="{Binding SetSelectedPropertyCommand}"
CommandParameter="Quantity" />
<Button
Text="{Binding Price}"
Command="{Binding SetSelectedPropertyCommand}"
CommandParameter="Price" />
<loc:Numpad>
<loc:Numpad.Triggers>
<DataTrigger
TargetType="loc:Numpad"
Binding="{Binding SelectedProperty}"
Value="Quantity">
<Setter
Property="Text"
Value="{Binding Quantity,Mode=TwoWay}" />
</DataTrigger>
<DataTrigger
TargetType="loc:Numpad"
Binding="{Binding SelectedProperty}"
Value="Price">
<Setter
Property="Text"
Value="{Binding Price,Mode=TwoWay}" />
</DataTrigger>
</loc:Numpad.Triggers>
</loc:Numpad>
</VerticalStackLayout>
</ContentPage>
Text
的 Numpad
绑定到 Quantity
或 UnitPrice
。Numpad
中的任何按钮都会更改前 2 个按钮中所选按钮的 Text
属性。不幸的是它不起作用,
Text
不会改变。
罪魁祸首是什么?
您可以将
UpCommand
和DownCommand
放入ItemViewModel
中,这样您就可以直接操作数量和价格,而无需使用触发器。
您不需要设置Reference扩展来设置
BindingContext
(或者甚至不需要TextProperty
来设置Numpad)。 <loc:Numpad>
将从其父级/MainPage继承BindingContext,也就是说小键盘的BindingContext默认为ItemViewModel。
//no need to set the BindingContext
<VerticalStackLayout>
<Button
Text="Up"
Command="{Binding UpCommand}" />
<Button
Text="Down"
Command="{Binding DownCommand}" />
</VerticalStackLayout>
并在ItemViewModel中,定义向上按钮和向下按钮的命令。
[RelayCommand]
void Up(string selectedProperty)
{
if (SelectedProperty == "Quantity")
Quantity += 1;
else
Price += 1;
}
[RelayCommand]
void Down(string selectedProperty)
{
if (SelectedProperty == "Quantity")
Quantity -= 1;
else
Price -= 1;
}
希望有帮助!