在我向用户显示收据的页面上,我有一个列出小计,任何税金和总额的部分。由于适用的税费因地区而异,并且根据所售产品而定,因此本节中的行数会有所不同。例如,这里有3个单独的订单,一个包含GST和PST,一个只有GST,另一个没有:
我通过在XAML中将SubTotal放在网格中,并在我从ViewModel调用的方法中将其余部分添加到代码隐藏中来完成此操作。但是,我真的很想避免这样做,所以我想知道是否有一种方法可以实现这一点,并不需要让ViewModel知道View。
由于多种原因,ListView
不适用于此:
ScrollView
内,ListView
内有ScrollView
会导致各种奇怪的问题。Grid
,但ListView
会占用其父级的整个宽度,无论如何。因此,如果没有ViewModel知道View 和而不诉诸ListView
,我可以做到这一点吗?
答案 0 :(得分:1)
封装所需功能以便视图和视图模型不耦合的一种方法是创建用户控件。
我创建了一个名为TotalsGridControl的新用户控件。这是XAML
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScratchPad.UserControls.TotalsGridControl"
x:Name="TotalsGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
这是背后的代码。
public partial class TotalsGridControl : Grid
{
public TotalsGridControl()
{
InitializeComponent();
}
public static readonly BindableProperty TotalsProperty =
BindableProperty.Create(nameof(Totals), typeof(List<TotalItem>), typeof(TotalsGridControl), null,
BindingMode.OneWay, null, OnTotalsChanged);
private static void OnTotalsChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var control = (TotalsGridControl)bindable;
if (control != null)
{
if (newvalue is List<TotalItem> totals)
{
var rowNumber = -1;
double grandTotal = 0;
foreach (var totalItem in totals)
{
grandTotal += totalItem.Value;
var descLabel = new Label {Text = totalItem.Description};
var valueLabel = new Label { Text = totalItem.Value.ToString("c") };
rowNumber++;
control.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto});
control.Children.Add(descLabel, 0, rowNumber);
control.Children.Add(valueLabel, 1, rowNumber);
}
var grandTotalDescLabel = new Label { Text = "Total" };
var grandTotalValueLabel = new Label { Text = grandTotal.ToString("c") };
rowNumber++;
control.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
control.Children.Add(grandTotalDescLabel, 0, rowNumber);
control.Children.Add(grandTotalValueLabel, 1, rowNumber);
}
}
}
public List<TotalItem> Totals
{
get => (List<TotalItem>)GetValue(TotalsProperty);
set => SetValue(TotalsProperty, value);
}
}
我使用了一个可绑定属性来允许将TotalItem列表绑定到用户控件。
以下是视图模型中的数据
public List<TotalItem> Totals { get; set; }
Totals = new List<TotalItem>
{
new TotalItem {Description = "SubTotal", Value = 99.91},
new TotalItem {Description = "GST", Value = 5.0},
new TotalItem {Description = "PST", Value = 4.9}
};
,这是页面中的XAML
<userControls:TotalsGridControl Totals="{Binding Totals}"/>
输出
答案 1 :(得分:0)
在:
public class ReceiptPageModel : PageModelBase
{
private Receipt _receipt;
public Receipt Receipt
{
get => _receipt;
private set => Set(ref _receipt, value);
}
public override void Init(object initData)
{
Receipt = (Receipt) initData;
((ReceiptPage) CurrentPage).AddTaxes(Receipt);
}
}
后:
public class ReceiptPageModel : PageModelBase
{
private Receipt _receipt;
public Receipt Receipt
{
get => _receipt;
private set => Set(ref _receipt, value);
}
public override void Init(object initData)
{
Receipt = (Receipt) initData;
}
}
public partial class ReceiptPage : FreshBaseContentPage
{
public ReceiptPage()
{
InitializeComponent();
BindingContextChanged += HandlePageModelAdded;
}
private void HandlePageModelAdded(object sender, EventArgs e)
{
var pageModel = (ReceiptPageModel)BindingContext;
if (pageModel.Receipt != null)
{
AddTaxes(pageModel.Receipt);
}
else
{
pageModel.PropertyChanged += (s, args) =>
{
if (args.PropertyName == nameof(pageModel.Receipt))
AddTaxes(pageModel.Receipt);
};
}
}
private void AddTaxes(Receipt receipt)
{
...
}
}