【问题标题】:DependencyProperty does not work if the value is from a binding如果值来自绑定,则 DependencyProperty 不起作用
【发布时间】:2020-01-26 19:58:06
【问题描述】:

我用 viewmodel 创建了 UserControl。它具有 DependencyProperty,仅在直接传递值时才有效。如果值是通过绑定传递的,它就不再起作用了。

查看代码如下:

这是一个不与任何其他元素关联的封闭元素。所有列出的物品都属于他。这是一个代码缩短,我不会展示完整的、不可估量的结构。

查看

public partial class SomeView : UserControl
{
    public SomeView()
    {
        InitializeComponent();
        SetBinding(ActiveProperty, new Binding(nameof(SomeViewModel.Active)) { Mode = BindingMode.OneWayToSource });
    }

    #region ActiveProperty
    public static readonly DependencyProperty ActiveProperty = DependencyProperty.Register(nameof(Active), typeof(bool), typeof(VNCBoxView));

    public bool Active
    {
        get { return (bool)GetValue(ActiveProperty); }
        set { SetValue(ActiveProperty, value); }
    }
}

VievModel

public class SomeViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool active;

    public bool Active
    {
        get { return active; }
        set
        {
            active = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Active)));
        }
    }
}

用户控制

<UserControl ...>
    <UserControl.DataContext>
        <viewModels:SomeViewModel />
    </UserControl.DataContext>
    <Grid>
        <TextBlock Text="{Binding Active}" />
    </Grid>
</UserControl>

================================================ ====

当使用现成的组件(它是一个单独的、独立的实体)时,问题的出现取决于它的使用方式。 我提醒您,相关视图中使用的元素是一个封闭的整体,与使用它的元素没有联系。问题在于价值的转移。

这是有效的用法:

<local:SomeView Active="True" />

在 viewmodel 中,setter 被调用两次,一次是 false,然后是 true。

如果值来自绑定,则不起作用:

<local:SomeView Active="{Binding SomeParentProperty}" />

在 viewmodel 中,setter 只被调用一次,值为 false。

在这两种情况下,视图中的设置器都不会被调用。

请帮忙

【问题讨论】:

  • 设置 UserControl 的 DataContext 会破坏继承。 IsConnected 是在哪里定义的,为什么要使用 SomeViewModel
  • @Clemens,请仔细阅读问题。它不会重复这些案例。他们正在谈论的内容完美无缺。没有人在使用地点遇到绑定问题。
  • 您可能还想阅读以下内容:stackoverflow.com/a/28815689/1136211
  • 如果“从不调用视图中的设置器”意味着不会调用 UserControl 的 Active 属性的 set 方法:这是因为 WPF 绕过它并直接调用 SetValue(ActiveProperty, ...) .您需要注册一个 PropertyChangedCallback 以便在依赖项属性更改时收到通知。
  • @Clemens,你在谈论我所知道的事情,关注与问题完全不同的问题。视图模型的存在也无关紧要。 PropertyChangedCallback 仅在直接给出值时才会调用,这是一个问题。一切正常或无济于事。

标签: c# wpf binding dependency-properties


【解决方案1】:

UserControl的当前DataContext中SomeViewModel实例中没有IsConnected属性,因此是Binding

<local:SomeView Active="{Binding IsConnected}" />

行不通。它会尝试根据当前 DataContext 解析 PropertyPath,除非您明确指定其 SourceRelativeSourceElementName

这正是 UserControl 应该从不显式设置它们自己的 DataContext 的确切原因,因此永远不会有像自己的私有视图模型这样的东西。

UserControl 的 XAML 中的元素不会绑定到此类私有视图模型对象的属性,而是直接绑定到 UserControl 的属性,例如像

<TextBlock Text="{Binding Active,
    RelativeSource={RelativeSource AncestorType=UserControl}}"/>

【讨论】:

  • 错字?应该是{Binding Active}
  • @Sinatr 否,如问题所示。 OP 似乎有一个具有该属性的“外部”视图模型。
  • "IsConnected" 是父级的属性,因为我们讨论的是使用 SomeView,而不是它的内容!
  • @T.Czubaszek 什么父母?你没有在你的问题中显示任何类似的东西,所以我们只能假设在 SomeView 的父元素的 DataContext 中有一个“外部”视图模型 - 具有 IsConnected 属性,例如一个窗口或页面。
【解决方案2】:

当您像这样在UserControl 中显式设置DataContext 时:

<UserControl.DataContext>
    <viewModels:SomeViewModel />
</UserControl.DataContext>

...您不能再像这样在消费视图中绑定到SomeViewDataContext

<local:SomeView Active="{Binding IsConnected}" />

...因为SomeViewModel 没有任何IsConnected 属性。

您应该避免显式设置DataContext 并让UserControl 从其父元素继承其DataContext。您仍然可以使用RelativeSourceElementName 绑定到UserControl 本身的依赖属性:

<UserControl ...>
    <Grid>
        <TextBlock Text="{Binding Active, RelativeSource={RelativeSource AncestorType=UserControl}}" />
    </Grid>
</UserControl>

此外,SomeViewModel 在您的示例中似乎是多余的,因为 UserControl 已经具有 Active 属性。

【讨论】:

  • "IsConnected" 是父级的属性,因为我们讨论的是使用 SomeView,而不是它的内容!
  • IsConnected&lt;local:SomeView&gt; 元素的DataContect 的属性。你想说什么?在此示例中,我将 Active 绑定到 IsConnected
猜你喜欢
  • 2011-12-25
  • 2012-04-15
  • 2018-12-07
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-10
相关资源
最近更新 更多