【发布时间】:2021-01-16 02:52:36
【问题描述】:
我想了解如何在 WPF 中编写适当的用户控件/视图模型。为了简单起见,我发明了以下示例:
说,我们有一个DateRange 类,定义为:
using System;
namespace MyDateApp
{
public class DateRange
{
public DateTime Start
{
get;
set;
} = new DateTime();
public int Length // in days
{
get;
set;
} = 0;
}
}
(为了论证,我们假设这个类不能以任何方式修改。)
类的一个实例被用作我们窗口的数据上下文:
using System;
using System.Windows;
namespace MyDateApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DateRange range = new DateRange();
range.Start = new DateTime(2020, 1, 1);
range.Length = 5;
DataContext = range;
}
}
}
我想实现一个自定义视图/控件,它允许应用程序的用户选择开始和结束日期,而不是开始日期和范围。它将被包裹在一个名为DateControl 的UserControl 中:
<Window x:Class="MyDateApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyDateApp">
<StackPanel>
<local:DateControl Range="{Binding}" />
</StackPanel>
</Window>
我能够得到这个DateControl 工作的基本实现:
using System;
using System.Windows;
using System.Windows.Controls;
namespace MyDateApp
{
public partial class DateControl : UserControl
{
public DateControl()
{
InitializeComponent();
}
public DateRange Range
{
get { return (DateRange)GetValue(RangeProperty); }
set { SetValue(RangeProperty, value); }
}
public static readonly DependencyProperty RangeProperty =
DependencyProperty.Register("Range", typeof(DateRange), typeof(DateControl), new PropertyMetadata(new DateRange()));
public DateTime End
{
get => Range.Start + new TimeSpan(Range.Length, 0, 0, 0);
set => Range.Length = (value - Range.Start).Days;
}
}
}
使用以下 XAML:
<UserControl x:Class="MyDateApp.DateControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyDateApp"
Name="UserControl">
<StackPanel Orientation="Horizontal">
<TextBlock Text="From:" />
<DatePicker SelectedDate="{Binding Range.Start, ElementName=UserControl}" />
<TextBlock Text="To:" />
<DatePicker SelectedDate="{Binding End, ElementName=UserControl}" />
</StackPanel>
</UserControl>
它非常适合开始日期,但是结束日期的值是错误的。因此,我的问题:
我怎样才能正确地实现这个?
我的成功条件是:
- 原始模型类必须保持不变,
- 并且用户控件必须更新主窗口数据上下文。
奖励: 我必须实现什么才能将此控件用作ListBoxItem?
【问题讨论】:
-
DataContext 会自动传递给您的 UserControl。不需要依赖属性。因此,您可以简单地绑定到 ViewModel 中的属性 Start 和 End
-
回答您的条件:“原始模型类必须保持不变”,然后可能从模型继承。保持 UI 尽可能的愚蠢。否则你总是依赖你的 UI 来处理业务逻辑。第二:这不是你的模型,而是你的视图模型。
-
@Klamsi “DataContext 会自动传递给您的 UserControl。”是什么意思?我可以在不绑定主窗口的情况下执行
<DatePicker SelectedDate="{Binding Range.Start, ElementName=UserControl}" />吗? -
@Klamsi 我想分离会很好,但我的业务逻辑必须存在于某个地方......我不确定如何执行你的想法。
标签: c# wpf xaml mvvm user-controls