如何将自定义依赖项 属性 绑定到控件的视图模型?
How to bind custom dependecy property to control's view model?
我需要创建一个输入/输出很少但内部功能很多的控件。我认为最好的方法是创建 Dependency Properties
用于与其他应用程序部分交互,并有一个 private
view model
隐藏功能。
这是我的样本:
Window
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication1">
<StackPanel>
<DatePicker x:Name="DatePicker" />
<app:MyControl DateCtrl="{Binding ElementName=DatePicker, Path=SelectedDate}" />
</StackPanel>
</Window>
我的控件
<UserControl x:Class="WpfApplication1.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication1">
<UserControl.DataContext>
<app:ViewModel />
</UserControl.DataContext>
<Grid>
<TextBlock Text="{Binding DateVM}" />
</Grid>
</UserControl>
控制代码隐藏
using System;
using System.Windows;
namespace WpfApplication1
{
public partial class MyControl
{
public MyControl()
{
InitializeComponent();
}
public static DependencyProperty DateCtrlProperty = DependencyProperty.Register("DateCtrl", typeof(DateTime), typeof(MyControl));
public DateTime DateCtrl
{
get { return (DateTime) GetValue(DateCtrlProperty); }
set { SetValue(DateCtrlProperty, value); }
}
}
}
视图模型
using System;
using System.ComponentModel;
namespace WpfApplication1
{
public class ViewModel : INotifyPropertyChanged
{
private DateTime _dateVM;
public DateTime DateVM
{
get { return _dateVM; }
set
{
_dateVM = value;
OnPropertyChanged("DateVM");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我需要实现的是将 DatePicker
中选择的 date
传播到 MyControl's
view model
。或者,有没有更好的模式可以使用?
您所描述的是一个常见的误解,即所有视图都应该有一个视图模型。但是,对于用作控件的 UserControl
s 来说,简单地使用它们自己的 DependencyProperty
s 通常要简单得多(也更合适)。
你的方法的问题是你在内部分配了UserControl DataContext
,所以它不能从控件外部设置。解决方案是 不 在内部设置 DataContext
,而是使用 RelativeSource Binding
访问 UserControl DependencyProperty
,如下所示:
<TextBlock Text="{Binding DateCtrl, RelativeSource={RelativeSource
AncestorType={x:Type YourLocalPrefix:MyControl}}}" />
如果你真的必须使用内部视图模型,那么声明一个 DependencyProperty
那个类型并且数据绑定到它,就像我在上面展示的一样:
<TextBlock Text="{Binding YourViewModelProperty.DateVM, RelativeSource={RelativeSource
AncestorType={x:Type YourLocalPrefix:MyControl}}}" />
DatePicker 应该有它自己的 DatePickerViewModel,它定义了一个 SelectedDate 属性 或依赖项 属性。您应该定义 DatePicker 控件的 XAML 以使用此专用 ViewModel。
然后,当您使用控件时,您可以像这样设置绑定:
<DatePicker SelectedDate="{Binding Path=DateVM,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
请注意,DateVM 不是日期选择器的 属性,而是消费视图模型(或在本例中为 Main Window)的 属性。打开选择器时,它将默认为datevm中已经设置的日期。
另一件事是您的选择器目前不允许任何选择 - 它只是一个文本块!
我需要创建一个输入/输出很少但内部功能很多的控件。我认为最好的方法是创建 Dependency Properties
用于与其他应用程序部分交互,并有一个 private
view model
隐藏功能。
这是我的样本:
Window
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication1">
<StackPanel>
<DatePicker x:Name="DatePicker" />
<app:MyControl DateCtrl="{Binding ElementName=DatePicker, Path=SelectedDate}" />
</StackPanel>
</Window>
我的控件
<UserControl x:Class="WpfApplication1.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication1">
<UserControl.DataContext>
<app:ViewModel />
</UserControl.DataContext>
<Grid>
<TextBlock Text="{Binding DateVM}" />
</Grid>
</UserControl>
控制代码隐藏
using System;
using System.Windows;
namespace WpfApplication1
{
public partial class MyControl
{
public MyControl()
{
InitializeComponent();
}
public static DependencyProperty DateCtrlProperty = DependencyProperty.Register("DateCtrl", typeof(DateTime), typeof(MyControl));
public DateTime DateCtrl
{
get { return (DateTime) GetValue(DateCtrlProperty); }
set { SetValue(DateCtrlProperty, value); }
}
}
}
视图模型
using System;
using System.ComponentModel;
namespace WpfApplication1
{
public class ViewModel : INotifyPropertyChanged
{
private DateTime _dateVM;
public DateTime DateVM
{
get { return _dateVM; }
set
{
_dateVM = value;
OnPropertyChanged("DateVM");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我需要实现的是将 DatePicker
中选择的 date
传播到 MyControl's
view model
。或者,有没有更好的模式可以使用?
您所描述的是一个常见的误解,即所有视图都应该有一个视图模型。但是,对于用作控件的 UserControl
s 来说,简单地使用它们自己的 DependencyProperty
s 通常要简单得多(也更合适)。
你的方法的问题是你在内部分配了UserControl DataContext
,所以它不能从控件外部设置。解决方案是 不 在内部设置 DataContext
,而是使用 RelativeSource Binding
访问 UserControl DependencyProperty
,如下所示:
<TextBlock Text="{Binding DateCtrl, RelativeSource={RelativeSource
AncestorType={x:Type YourLocalPrefix:MyControl}}}" />
如果你真的必须使用内部视图模型,那么声明一个 DependencyProperty
那个类型并且数据绑定到它,就像我在上面展示的一样:
<TextBlock Text="{Binding YourViewModelProperty.DateVM, RelativeSource={RelativeSource
AncestorType={x:Type YourLocalPrefix:MyControl}}}" />
DatePicker 应该有它自己的 DatePickerViewModel,它定义了一个 SelectedDate 属性 或依赖项 属性。您应该定义 DatePicker 控件的 XAML 以使用此专用 ViewModel。
然后,当您使用控件时,您可以像这样设置绑定:
<DatePicker SelectedDate="{Binding Path=DateVM,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
请注意,DateVM 不是日期选择器的 属性,而是消费视图模型(或在本例中为 Main Window)的 属性。打开选择器时,它将默认为datevm中已经设置的日期。
另一件事是您的选择器目前不允许任何选择 - 它只是一个文本块!