如何实现MVVM自定义控件?

时间:2016-03-14 22:02:18

标签: wpf mvvm custom-controls

我有费用屏幕,其中包含一个文本框,我可以在其中列出费用的价格。由于我为这个文本框构建了很多逻辑(验证等),我想将它提取到一个单独的控件并在其他屏幕上重用它。我试图以mvvm风格构建它。这就是我现在所拥有的:

ExpenseView

<page>
    <Label Text={Binding Date} />
    <wpfControls:CurrencyTextBoxView ViewModel="{Binding PriceViewModel}" />
</page>

ExpenseViewModel

public class ExpenseViewModel : INotifyPropertyChanged
{
  private ExpenseModel Model { get; }

  public string Date
  {
     get { return Model.Date.ToString(); }
     set 
     { 
       Model.Date = DateTime.Parse(value); 
       RaisePropertyChanged();
     }
  }

  private CurrencyTextBoxViewModel _priceViewModel;
  public CurrencyTextBoxViewModel PriceViewModel
  {
     get { return _priceViewModel; }
     set { _priceViewModel = value; }
  }
}

ExpenseModel

public class ExpenseModel
{
    public DateTime Date { get; set; }
    public decimal Price { get; set; } // This is the bit I don't know how to implement correctly
}

CurrencyTextBoxView

<control>
    <TextBox Content={Binding Price} />
</control>

CurrencyTextBoxViewModel

public class CurrencyTextBoxViewModel : INotifyPropertyChanged
{
  private CurrencyModel Model { get; }

  public string Price
  {
     get { return Model.Price.ToString(); }
     set 
     { 
       Model.Price = decimal.Parse(value); 
       RaisePropertyChanged();
     }
  }
}

CurrencyModel

public class CurrencyModel
{
  public decimal Price { get; set; }
}

现在的问题是:我需要在我的ExpenseModel中拥有Price属性(因为它被保存在数据库中)。我不想在我的CurrencyModel中使用Date属性(因为并非总是有意义)。

我应该将CurrencyModel保留在我的ExpenseModel中吗?当货币文本框中的文本发生变化时,如何有效地更新它? 此外,ExpenseModel位于与我的其他类不同的项目中,我不希望使用CurrencyModel使该项目依赖于该项目。

每当CurrencyTextBoxViewModel.Price字符串更改时,我应该从CurrencyTextBoxViewModel监听PropertyChanged事件并更新ExpenseModel.Price吗?我喜欢我的视图模型充当视图模型解析器的方式(Date属性示例)。有没有办法实现PriceViewModel,以便其getter直接从ExpenseModel返回数据(因此它充当解析器)?

我知道有很多方法可以实现它,但我正在寻找最符合mvvm的方法。另外,我不确定我是否正确实现了整个模式?

1 个答案:

答案 0 :(得分:0)

对于Date属性,如果不需要序列化,则只将其放在视图模型上。

我该怎么做: 如果您想重用CurrencyTextBox,我不会将控件与模型联系起来。不需要CurrencyModel。在DependencyProperty上准备CurrencyText(说CurrencyTextBox)。视图如下:

<xxx:CurrencyTextBox CurrencyText="{Binding Currency}" />

您可以省略CurrencyTextBoxViewModel,因为CurrencyText可以绑定到内部TextBox.Text(或者只更新视图模型上的相关属性)。无论如何,通过双向绑定,当CurrencyText更新时,ExpenseViewModel.Currency也会更新,您可以在这里更新模型。

我认为听模型的事件是可以的,因为视图模型比模型短。但是,如果新值与旧值相同,则应阻止传播事件触发。

该模型充当数据的起源并执行业务逻辑。视图模型只是模型的阴影,因此它通常很薄。考虑使用一些MVVM框架来理解它。