Xamarin 条目绑定到 MVVM
Xamarin Entry Binding to MVVM
我正在尝试使用 MVVM 而不是代码隐藏来实现我能做的一切,但是如果我有很多对象需要在条目更改时访问,我根本不知道如何做好。
Xaml:
<Entry x:Name="UpdatedCost"
TextChanged="UpdatedCost_TextChanged"/>
<Label x:Name="PriceDifLabel"/>
<Entry x:Name="CurrentCost"
Text="2.5"/>
<Entry x:Name="CurPriceUpdatedCostProfit"
Text="22%"/>
代码隐藏:
private void UpdatedCost_TextChanged(object sender, TextChangedEventArgs e)
{
if (double.TryParse(e.NewTextValue, out double UpdatedCost))
{
double diff = UpdatedCost - double.Parse(CurrentCost.Text);
string sign = diff > 0 ? "+" : "";
PriceDifLabel.Text = "(" + sign + string.Format("{0:0.0}", diff) +")";
PriceDifLabel.TextColor = diff > 0 ? Color.Red : Color.Green;
PriceDifLabel.BackgroundColor = Color.Yellow;
CurPriceUpdatedCostProfit.Text = ((int)((double.Parse(CurrentPrice.Text) - UpdatedCost) /
double.Parse(CurrentPrice.Text) * 100)).ToString() + "%";
}
}
如果能尽可能详细地帮助我将此方法转换为 MVVM 实现,我将不胜感激。如果相关,我的视图模型正在实现 MvvmHelpers.
的 BaseViewModel
非常感谢!
是的,您可以创建模型并为不同的控件创建不同的属性。
我根据您的代码创建了一个简单的演示(以 PriceDifLabel
的文本和文本颜色为例)。
您可以参考以下代码:
1.create 模型 MyViewModel.cs
并实现接口 INotifyPropertyChanged
。
并且当我们改变UpdatedCost
的值时(bind for Entry UpdatedCost
),我们也可以相应地改变PriceDif
。
MyViewModel.cs
public class MyViewModel: INotifyPropertyChanged
{
double _updatedCost;
public double UpdatedCost
{
set {
SetProperty(ref _updatedCost, value);
double diff = UpdatedCost - double.Parse(CurrentCost);
string sign = diff > 0 ? "+" : "";
PriceDif = "(" + sign + string.Format("{0:0.0}", diff) + ")";
PriceDifLabelColor = diff > 0 ? Color.Red : Color.Green;
System.Diagnostics.Debug.WriteLine("----------> PriceDif = " + PriceDif);
}
get { return _updatedCost; }
}
string _currentCost;
public string CurrentCost
{
set { SetProperty(ref _currentCost, value); }
get { return _currentCost; }
}
string _priceDif;
public string PriceDif
{
set { SetProperty(ref _priceDif, value); }
get { return _priceDif; }
}
Color _priceDifLabelColor = Color.Green;
public Color PriceDifLabelColor
{
set { SetProperty(ref _priceDifLabelColor, value); }
get { return _priceDifLabelColor; }
}
public MyViewModel() {
CurrentCost = "2.5";
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
2.bind 这些属性在 page.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:testapp1="clr-namespace:TestApp1"
x:Class="TestApp1.TestPage2">
<ContentPage.BindingContext>
<testapp1:MyViewModel></testapp1:MyViewModel>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Entry x:Name="UpdatedCost" Text="{Binding UpdatedCost}" />
<Label x:Name="PriceDifLabel" Text="{ Binding PriceDif}" TextColor="{Binding PriceDifLabelColor}"/>
<Entry x:Name="CurrentCost" Text="2.5"/>
<Entry x:Name="CurPriceUpdatedCostProfit" Text="22%"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
更多关于INotifyPropertyChanged
界面,您可以查看:
1.Hello,你可以创建这个BaseViewModel,然后把它传给每一个ViewModel,这样你就不用总是为每一个ViewModel单独创建INotifyPropertyChanged接口了。
然后你可以像这里一样将它继承到任何 ViewModel:
using YourApp.ViewModels
...
public class YourViewModel : BaseViewModel {
....}
//This is the BaseViewModel:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace YourApp.ViewModel
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
//declares the (required) PropertyChanged event that is defined by
//the interface.
public event PropertyChangedEventHandler PropertyChanged;
// next it is checked if someone has registered for the event,
// and in this case the event will be raised with the name of the
//property being updated.
protected void OnPropertyChanged([CallerMemberName] string
propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
// This is a helper method to make setting the property easier.
// Right now you can just take this with faith
// or if you are familiar with generics you can study it a little to
// see how it works.
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
}
}
我正在尝试使用 MVVM 而不是代码隐藏来实现我能做的一切,但是如果我有很多对象需要在条目更改时访问,我根本不知道如何做好。
Xaml:
<Entry x:Name="UpdatedCost"
TextChanged="UpdatedCost_TextChanged"/>
<Label x:Name="PriceDifLabel"/>
<Entry x:Name="CurrentCost"
Text="2.5"/>
<Entry x:Name="CurPriceUpdatedCostProfit"
Text="22%"/>
代码隐藏:
private void UpdatedCost_TextChanged(object sender, TextChangedEventArgs e)
{
if (double.TryParse(e.NewTextValue, out double UpdatedCost))
{
double diff = UpdatedCost - double.Parse(CurrentCost.Text);
string sign = diff > 0 ? "+" : "";
PriceDifLabel.Text = "(" + sign + string.Format("{0:0.0}", diff) +")";
PriceDifLabel.TextColor = diff > 0 ? Color.Red : Color.Green;
PriceDifLabel.BackgroundColor = Color.Yellow;
CurPriceUpdatedCostProfit.Text = ((int)((double.Parse(CurrentPrice.Text) - UpdatedCost) /
double.Parse(CurrentPrice.Text) * 100)).ToString() + "%";
}
}
如果能尽可能详细地帮助我将此方法转换为 MVVM 实现,我将不胜感激。如果相关,我的视图模型正在实现 MvvmHelpers.
的 BaseViewModel非常感谢!
是的,您可以创建模型并为不同的控件创建不同的属性。
我根据您的代码创建了一个简单的演示(以 PriceDifLabel
的文本和文本颜色为例)。
您可以参考以下代码:
1.create 模型 MyViewModel.cs
并实现接口 INotifyPropertyChanged
。
并且当我们改变UpdatedCost
的值时(bind for Entry UpdatedCost
),我们也可以相应地改变PriceDif
。
MyViewModel.cs
public class MyViewModel: INotifyPropertyChanged
{
double _updatedCost;
public double UpdatedCost
{
set {
SetProperty(ref _updatedCost, value);
double diff = UpdatedCost - double.Parse(CurrentCost);
string sign = diff > 0 ? "+" : "";
PriceDif = "(" + sign + string.Format("{0:0.0}", diff) + ")";
PriceDifLabelColor = diff > 0 ? Color.Red : Color.Green;
System.Diagnostics.Debug.WriteLine("----------> PriceDif = " + PriceDif);
}
get { return _updatedCost; }
}
string _currentCost;
public string CurrentCost
{
set { SetProperty(ref _currentCost, value); }
get { return _currentCost; }
}
string _priceDif;
public string PriceDif
{
set { SetProperty(ref _priceDif, value); }
get { return _priceDif; }
}
Color _priceDifLabelColor = Color.Green;
public Color PriceDifLabelColor
{
set { SetProperty(ref _priceDifLabelColor, value); }
get { return _priceDifLabelColor; }
}
public MyViewModel() {
CurrentCost = "2.5";
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
2.bind 这些属性在 page.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:testapp1="clr-namespace:TestApp1"
x:Class="TestApp1.TestPage2">
<ContentPage.BindingContext>
<testapp1:MyViewModel></testapp1:MyViewModel>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Entry x:Name="UpdatedCost" Text="{Binding UpdatedCost}" />
<Label x:Name="PriceDifLabel" Text="{ Binding PriceDif}" TextColor="{Binding PriceDifLabelColor}"/>
<Entry x:Name="CurrentCost" Text="2.5"/>
<Entry x:Name="CurPriceUpdatedCostProfit" Text="22%"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
更多关于INotifyPropertyChanged
界面,您可以查看:
1.Hello,你可以创建这个BaseViewModel,然后把它传给每一个ViewModel,这样你就不用总是为每一个ViewModel单独创建INotifyPropertyChanged接口了。 然后你可以像这里一样将它继承到任何 ViewModel:
using YourApp.ViewModels
...
public class YourViewModel : BaseViewModel {
....}
//This is the BaseViewModel:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace YourApp.ViewModel
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
//declares the (required) PropertyChanged event that is defined by
//the interface.
public event PropertyChangedEventHandler PropertyChanged;
// next it is checked if someone has registered for the event,
// and in this case the event will be raised with the name of the
//property being updated.
protected void OnPropertyChanged([CallerMemberName] string
propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
// This is a helper method to make setting the property easier.
// Right now you can just take this with faith
// or if you are familiar with generics you can study it a little to
// see how it works.
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
}
}