依赖项 属性 未从 ViewModel 设置
Dependency Property not set from ViewModel
我创建了一个自定义控件 "CustomAutoCompleteBox"(继承自 AutoCompleteBox),具有一个依赖项 属性 "CurrentItem".
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("CurrentItem", typeof(CityEntity), typeof(CustomAutoCompleteBox),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CityEntity CurrentItem
{
get { return (CityEntity)GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
此自定义控件还有一个 属性 "InternalCurrentItem"。
public CityEntity InternalCurrentItem
{
get { return _internalCurrentCity; }
set
{
if (_internalCurrentCity == value) return;
_internalCurrentCity = value;
OnPropertyChanged();
CurrentItem = value;
}
}
DataContext 在构造函数中为自己定义:
public VilleAutoCompleteBox()
{
DataContext = this;
...
}
样式设置 ItemsSource 和 SelectedItem 如下:
<Style TargetType="{x:Type infrastructure_controls:CustomAutoCompleteBox}" BasedOn="{StaticResource AutoCompleteBoxFormStyle}">
<Setter Property="ItemsSource" Value="{Binding InternalItems, Mode=OneWay}" />
<Setter Property="SelectedItem" Value="{Binding InternalCurrentItem, Mode=TwoWay}" />
...
</Style>
总而言之,ItemsSource 绑定到内部 属性 "InternalItems",SelectedItem 绑定到内部 属性 "InternalCurrentItem".
为了使用它,我这样声明这个 CustomAutoCompleteBox :
<infrastructure_usercontrols:CustomAutoCompleteBox Width="200" CurrentItem="{Binding DataContext.VmCurrentItem, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay}" />
我已经将依赖项 属性 "CurrentItem" 绑定到 ViewModel 的 属性 "VmCurrentItem".
除一件事外一切正常。
当我在控件中键入文本时,InternalCurrentItem 属性 会正确更改。与我的 ViewModel 中的 CurrentItem 属性 相同。
具体来说,InternalCurrentItem 被正确修改(设置)。此 属性 设置 CurrentItem 依赖项 属性,此依赖项 属性 设置 VmCurrentItem.
反之则不然。如果我直接更改 ViewModel 中 VmCurrentItem 属性 的值,则 CurrentItem 属性 不会更改。我不明白为什么。
您需要以与第一个相同的方式声明 属性:
public static readonly DependencyProperty InternalCurrentItemProperty =
DependencyProperty.Register("InternalCurrentItem", typeof(CityEntity), typeof(CustomAutoCompleteBox),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CityEntity InternalCurrentItem
{
get{ return (CityEntity)GetValue(InternalCurrentItemProperty); }
set
{
SetValue(InternalCurrentItemProperty, value);
}
}
第一种情况导致以下事件链:
SelectedItem
已更改
InternalCurrentItem
由于绑定 由框架更新
- 您在
InternalCurrentItem
setter 中手动更新 CurrentItem
VmCurrentItem
由于绑定 由框架更新
相反的方向是这样的:
VmCurrentItem
已更改
CurrentItem
由于绑定 由框架更新
...就是这样。当 CurrentItem
更改时,没有任何绑定,也没有任何代码会更新 InternalCurrentItem
。因此,您需要做的是为您的 CurrentItemProperty
注册一个 PropertyChangedCallback
,这将更新 InternalCurrentItem
:
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register(
"CurrentItem",
typeof(CityEntity),
typeof(CustomAutoCompleteBox),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback = CurrentItemPropertyChanged
});
private static void CurrentItemPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (CustomAutoCompleteBox)d;
control.InternalCurrentItem = (CityEntity)e.NewValue;
}
我创建了一个自定义控件 "CustomAutoCompleteBox"(继承自 AutoCompleteBox),具有一个依赖项 属性 "CurrentItem".
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("CurrentItem", typeof(CityEntity), typeof(CustomAutoCompleteBox),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CityEntity CurrentItem
{
get { return (CityEntity)GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
此自定义控件还有一个 属性 "InternalCurrentItem"。
public CityEntity InternalCurrentItem
{
get { return _internalCurrentCity; }
set
{
if (_internalCurrentCity == value) return;
_internalCurrentCity = value;
OnPropertyChanged();
CurrentItem = value;
}
}
DataContext 在构造函数中为自己定义:
public VilleAutoCompleteBox()
{
DataContext = this;
...
}
样式设置 ItemsSource 和 SelectedItem 如下:
<Style TargetType="{x:Type infrastructure_controls:CustomAutoCompleteBox}" BasedOn="{StaticResource AutoCompleteBoxFormStyle}">
<Setter Property="ItemsSource" Value="{Binding InternalItems, Mode=OneWay}" />
<Setter Property="SelectedItem" Value="{Binding InternalCurrentItem, Mode=TwoWay}" />
...
</Style>
总而言之,ItemsSource 绑定到内部 属性 "InternalItems",SelectedItem 绑定到内部 属性 "InternalCurrentItem".
为了使用它,我这样声明这个 CustomAutoCompleteBox :
<infrastructure_usercontrols:CustomAutoCompleteBox Width="200" CurrentItem="{Binding DataContext.VmCurrentItem, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay}" />
我已经将依赖项 属性 "CurrentItem" 绑定到 ViewModel 的 属性 "VmCurrentItem".
除一件事外一切正常。
当我在控件中键入文本时,InternalCurrentItem 属性 会正确更改。与我的 ViewModel 中的 CurrentItem 属性 相同。
具体来说,InternalCurrentItem 被正确修改(设置)。此 属性 设置 CurrentItem 依赖项 属性,此依赖项 属性 设置 VmCurrentItem.
反之则不然。如果我直接更改 ViewModel 中 VmCurrentItem 属性 的值,则 CurrentItem 属性 不会更改。我不明白为什么。
您需要以与第一个相同的方式声明 属性:
public static readonly DependencyProperty InternalCurrentItemProperty =
DependencyProperty.Register("InternalCurrentItem", typeof(CityEntity), typeof(CustomAutoCompleteBox),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CityEntity InternalCurrentItem
{
get{ return (CityEntity)GetValue(InternalCurrentItemProperty); }
set
{
SetValue(InternalCurrentItemProperty, value);
}
}
第一种情况导致以下事件链:
SelectedItem
已更改InternalCurrentItem
由于绑定 由框架更新
- 您在
InternalCurrentItem
setter 中手动更新 VmCurrentItem
由于绑定 由框架更新
CurrentItem
相反的方向是这样的:
VmCurrentItem
已更改CurrentItem
由于绑定 由框架更新
...就是这样。当 CurrentItem
更改时,没有任何绑定,也没有任何代码会更新 InternalCurrentItem
。因此,您需要做的是为您的 CurrentItemProperty
注册一个 PropertyChangedCallback
,这将更新 InternalCurrentItem
:
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register(
"CurrentItem",
typeof(CityEntity),
typeof(CustomAutoCompleteBox),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback = CurrentItemPropertyChanged
});
private static void CurrentItemPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (CustomAutoCompleteBox)d;
control.InternalCurrentItem = (CityEntity)e.NewValue;
}