C# 未从ViewModel设置依赖项属性

C# 未从ViewModel设置依赖项属性,c#,wpf,xaml,binding,custom-controls,C#,Wpf,Xaml,Binding,Custom Controls,我创建了一个自定义控件“CustomAutoCompleteBox”(继承AutoCompleteBox),其中包含一个依赖属性“CurrentItem” 此自定义控件还有一个属性“InternalCurrentItem” DataContext在构造函数中自己定义: public VilleAutoCompleteBox() { DataContext = this; ... } 样式集ItemsSource和SelectedItem如下所示

我创建了一个自定义控件“CustomAutoCompleteBox”(继承AutoCompleteBox),其中包含一个依赖属性“CurrentItem”

此自定义控件还有一个属性“InternalCurrentItem”

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

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); }
    }
public CityEntity InternalCurrentItem
    {
        get { return _internalCurrentCity; }

        set
        {
            if (_internalCurrentCity == value) return;

            _internalCurrentCity = value;
            OnPropertyChanged();

            CurrentItem = value;
        }
    }

事实并非如此。如果我直接更改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
    设置程序中手动更新
    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;
}

附加精度小:当我在ViewModel中直接更改VmCurrentItem属性的值时,CurrentItem属性不会更改。但事实恰恰相反。修改CurrentItem时,VmCurrentItem已更改。问题不是来自InternalCurrentItem。谢谢您非常清晰准确的回答。但我带来了一点修正。与此相反,CurrentItem不会更新:(这是我不理解的一点。如果正确修改了CurrentItem,我将不得不手动更改InternalCurrentItem,如您的示例所示。是的,我刚刚注意到。您的视图模型是否会引发
属性更改
?您是否在输出窗口中收到任何与绑定相关的消息?此外,如果您使用某种view-model注入确保您正在修改控件绑定到的同一视图模型实例。是的,ViewModel提升属性已更改:public CityEntity VmCurrentItem{get{return}VmCurrentItem;}set{if(_VmCurrentItem==value)return;_vmCurrentItem=value;OnPropertyChanged(()=>vmCurrentItem);}输出窗口中没有任何内容。我通过添加PropertyChangedCallBack解决了此问题。请注意,通常不应将控件的DataContext设置为自身,因为这会阻止控件继承其父控件或窗口的DataContext。当您查看当前的复杂性时,可以很容易找到此规则的证据ntItem绑定。最好简单地使用RelativeSource编写控件的“内部”绑定。例如,请参阅以下答案:我已按照您的建议更新了代码。这更简洁,但无法解决问题。