C# 如何在UserControl中扩展模型?
我想了解如何在WPF中编写适当的用户控件/视图模型。为了简单起见,我发明了以下示例: 比如说,我们有一个C# 如何在UserControl中扩展模型?,c#,wpf,xaml,mvvm,user-controls,C#,Wpf,Xaml,Mvvm,User Controls,我想了解如何在WPF中编写适当的用户控件/视图模型。为了简单起见,我发明了以下示例: 比如说,我们有一个DateRange类,定义为: 使用系统; 名称空间MyDateApp { 公共类日期范围 { 公共日期时间开始 { 得到; 设置 }=新的日期时间(); 公共整数长度//以天为单位 { 得到; 设置 } = 0; } } (为了便于论证,我们假设该类不能以任何方式修改。) 类的实例用作窗口的数据上下文: 使用系统; 使用System.Windows; 名称空间MyDateApp { 公共部
DateRange
类,定义为:
使用系统;
名称空间MyDateApp
{
公共类日期范围
{
公共日期时间开始
{
得到;
设置
}=新的日期时间();
公共整数长度//以天为单位
{
得到;
设置
} = 0;
}
}
(为了便于论证,我们假设该类不能以任何方式修改。)
类的实例用作窗口的数据上下文:
使用系统;
使用System.Windows;
名称空间MyDateApp
{
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
DateRange=new DateRange();
range.Start=新日期时间(2020,1,1);
范围:长度=5;
数据上下文=范围;
}
}
}
我想实现一个自定义视图/控件,它允许应用程序的用户选择开始日期和结束日期,而不是开始日期和范围。它将被包装在名为DateControl
的UserControl
中:
我能够得到这个DateControl
工作的基本实现:
使用系统;
使用System.Windows;
使用System.Windows.Controls;
名称空间MyDateApp
{
公共部分类DateControl:UserControl
{
公共数据控制()
{
初始化组件();
}
公共日期范围
{
获取{return(DateRange)GetValue(RangeProperty);}
set{SetValue(RangeProperty,value);}
}
公共静态只读DependencyProperty RangeProperty=
Register(“Range”、typeof(DateRange)、typeof(DateControl)、newpropertyMetadata(new DateRange());
公共日期时间结束
{
get=>Range.Start+newtimespan(Range.Length,0,0,0);
set=>Range.Length=(value-Range.Start).Days;
}
}
}
使用以下XAML:
它适用于开始日期,但结束日期的值是错误的。因此,我的问题是:
我怎样才能正确地实现这一点
我成功的条件是:
- 原始模型类必须保持不变
- 用户控件必须更新主窗口数据上下文
好处:我必须实现什么才能将此控件用作
ListBoxItem
?创建一个位于视图和模型之间的视图模型,并将视图中的控件绑定到视图模型,而不是直接绑定到视图,例如:
public class ViewModel
{
//error handling and validation omitted for brevity...
private readonly DateRange _model = new DateRange();
private DateTime _startDate;
public DateTime StartDate
{
get
{
return _model.Start;
}
set
{
_model.Start = value;
}
}
private DateTime _endDate;
public DateTime EndDate
{
get { return _endDate; }
set
{
_endDate = value;
_model.Length = (int)_endDate.Date.Subtract(_startDate.Date).TotalDays;
}
}
}
直接向视图公开模型通常是个坏主意 这包括“包装”模型属性的方法 这对于普通的应用程序来说是可行的,但是您会发现大量的边缘情况使得它不具有吸引力。 例如,用户编辑模型类。 验证失败。 您的模型中现在有错误的数据。 它也相当笨重 我建议将模型类作为DTO来考虑 使用相应的属性和您不可避免地需要的额外属性构建viewmodel 实例化该视图模型,并从模型中复制数据以将其显示给视图 数据库>模型>视图模型>视图 在编辑/插入时,执行相反的操作并实例化一个模型以传递回存储库或实体框架 视图>视图模型>模型>数据库 这样,您的DataAnnotation就可以愉快地生活在viewmodel中,而不会污染模型。如果您使用的是ORM,比如实体框架,那么这将非常方便 对于特别复杂的场景,您甚至可能需要另一层用于特定于域的逻辑的类
对属性的直接复制,请考虑AutoPaul.
编辑: 使用这种方法,viewmodel与模型完全断开连接,因此视图不会更改它。从而满足要求1 此视图模型应由mainwindowviewmodel作为私有成员实例化。主窗口的公共属性将设置为实例。对于列表,属性将是这些viewmodels的列表或observablecollection我会考虑删除USER控件中的依赖属性,而将逻辑放进新的VIEW模型。
我不明白这个逻辑到底是什么,但我希望你不会对你设计的每个viewmodel提出问题,这里的任何答案都应该说明原理 因此,viewmodel可能看起来像:public class DateRangeViewModel : BindableBase
{
public DateRangeViewModel(DateTime _datefrom, int _length)
{
length = _length;
fromDate = _datefrom;
setUpDate();
}
private void setUpDate()
{
ToDate = ((DateTime)fromDate).AddDays(length);
}
private int length = 0;
public int Length
{
get => length;
set { setUpDate(); SetProperty(ref length, value, nameof(Length)); }
}
private DateTime? fromDate;
public DateTime? FromDate
{
get => fromDate;
set => SetProperty(ref fromDate, value, nameof(FromDate));
}
private DateTime? toDate;
public DateTime? ToDate
{
get => toDate;
set { setUpDate(); SetProperty(ref fromDate, value, nameof(ToDate)); }
}
}
windowviewmodel读取数据,这些数据来自作为模型的任何地方
对于每个新建的对象,都会创建一个DateRangeViewModel,将fromdate和length属性传递给ctor。数据上下文会自动传递给用户控件。不需要依赖项属性。因此,您可以简单地绑定到ViewModel中的属性开始和结束,并回答您的条件:“原始模型类必须保持不变”,然后可能从模型继承。让用户界面尽可能的愚蠢。否则,业务逻辑总是依赖于UI。第二:这不是您的模型,而是您的viewmodel。@Klamsi“DataContext自动传递给您的UserControl”是什么意思?我可以只做
而不在主窗口绑定?@Klamsi我想分离会很好,但我的业务逻辑必须存在于某个地方。。。我不知道我将如何执行你的想法。我以前已经了解了你所说的基本要点。然而,我的问题是,虽然我可能在概念层面上理解它,但我无法将其转化为代码。视频创作者和博客作者遗漏了所有这些小的实现细节。这些事实上可能微不足道