2017-12-08 13 views
0

사용자에게 영수증을 표시하고있는 페이지에서 소계, 세금 및 총액을 나열하는 섹션이 있습니다. 적용 가능한 세금은 지역에 따라 다르며 판매되는 제품에 따라 다르므로이 섹션의 행 수는 다양합니다. 나는 이것을 달성 한Xamarin.Forms : VIEW에 호출하는 ViewModel없이 그리드에 행을 동적으로 추가 할 수 있습니까?

GST+PST

GST Only

No Tax

: 예를 들어, 다음은 3 개 별도의 주문, GST와 PST 단지 GST 하나, 하나와 하나의도는 XAML의 모눈에 SubTotal 만 넣고 나머지는 ViewModel에서 호출하는 메서드의 코드 숨김에 추가합니다. 그러나, 나는 정말 이런 식으로 일을 피하고 싶습니다, 그래서 ViewModel보기에 대해 알 필요가없는 이것을 달성하기위한 접근 방식이 있는지 궁금하네요.

ListView는 이유로 여기에 적합하지 않습니다 :

  • 이 컨트롤은 ScrollView의 내부에, 그리고 모든 종류의 이상한 문제의 ScrollView 원인의 내부 ListView 데.
  • 열을 가장 넓은 요소만큼 좁게 유지하고 싶습니다. 이것은 Grid으로 가능하지만 ListView은 부모의 전체 너비를 차지합니다.
  • 나는

그래서 뷰 ​​모델이 ListView를 사용에 의지하지 않고보기 모르게이 작업을 수행 할 수있는 방법이 필요하지 않고 내 행을 선택할 수 원하는 어느 쪽?

+1

출력되는보기 모델의 데이터입니다 코드가 아니라 VM이 있어야하며 View의 코드 숨김이 아닌 이유는 무엇입니까? VM에서이 작업을 수행하면 MVVM이 심각하게 손상됩니다. View의 코드가 VM의 행 수에 따라 업데이트되지 않는 이유는 무엇입니까? – Jason

+0

흠, 이제 나는 두 가지 질문에 나쁘게 말하고 잘못된 생각을하고있었습니다. 내가 뭘하고 싶은 건 ViewModel에서 행을 추가하는 것이 아니라 ViewModel에 뷰에 대해 알리지 않고 행을 추가 할 수 있습니다. 그러나 이제는이 방법으로 보았습니다. 해결책은 분명합니다. 정말 고마워요! – Katie

+0

GST 및 PST에 대해 자동 크기 조정 행을 만들고 숨길 필요는 없습니까? 추신. FreshMvvm을 사용하여 당신을 만나서 반가워요! –

답변

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} 
}; 

여기 페이지

<userControls:TotalsGridControl Totals="{Binding Totals}"/> 

에서 XAML 그리고 당신은에서 그것을 할 수

enter image description here

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) 
    { 
     ... 
    } 
} 
+0

이것은 여전히 ​​페이지와 페이지 모델을 연결합니다. 다른 하나에 대해 알지 못한다. –

+0

@SteveChadbourne 어떻게하면 이걸 조정하겠습니까? 어느 누구도 다른 것에 대해 알지 못하면서이 일을 성취 할 수있는 방법이 있습니까? – Katie

+0

나는이를 위해 사용자 정의 컨트롤을 사용하는 방법을 보여주는 대답을 추가했다. –