XAML:如何将一个DependencyProperty绑定到另一个对象上同名的C#属性?

6

使用:

  • Visual Studio Community Edition 2015
  • .Net 4.0

我已经实现了这个答案,创建了自己的CheckBox类,并添加了一个IsCheckedDependencyProperty。该属性由WPF CheckBox上的IsChecked属性支持,但是如果工作正常的话,它将调用我的getter和setter函数。

如果我将我的属性重命名为IsChecked_temp并修改XAML以匹配,则可以正常工作。我认为这是一个命名冲突,但为什么ElementName不能解决它?以下是我的最小测试用例。

编辑0:我忘记提到,我没有收到任何错误或警告。

编辑1:这个答案最初被接受是因为它适用于测试用例,但显然不是完整的答案。将其应用于我的项目(并将CheckBox类重命名为ToggleBox)会在每次使用该属性时产生XamlParseException

无法在DependecyObject的依赖属性“IsChecked”上设置绑定。绑定只能在DependencyObject的DependencyProperty上设置。

我会尝试创建一个最小测试用例来演示这一点。

CheckBox.xaml

<UserControl x:Class="CheckBox_test.CheckBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="Self">
    <StackPanel>
        <CheckBox IsChecked="{Binding IsChecked, ElementName=Self}" />
    </StackPanel>
</UserControl>

CheckBox.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace CheckBox_test
{
    public partial class CheckBox : UserControl
    {
        public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
             "IsChecked",
             typeof(bool),
             typeof(CheckBox),
             new FrameworkPropertyMetadata(false,
                     FrameworkPropertyMetadataOptions.AffectsRender));

        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }

        public CheckBox()
        {
            InitializeComponent();
        }
    }
}

MainWindow.xaml

<Window x:Class="CheckBox_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CheckBox_test">
    <Grid>
        <local:CheckBox />
    </Grid>
</Window>

MainWindow.xaml.cs (for completeness)

using System.Windows;

namespace CheckBox_test
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

1
只是为了测试,尝试编写 IsChecked="{Binding Path=IsChecked, ElementName=Self}"。 - Spawn
1
@Spawn 我尝试过加上和不加上“_temp”,但结果都是一样的。不过还是谢谢你的建议。 - Grault
好的,我明天会尝试... Self对于UserControl来说并不是一个罕见的名称,所以它应该可以工作。你能告诉我你使用的Visual Studio和.NET版本吗? - Spawn
我已经将那些细节编辑进了问题中。 - Grault
2
@kirotab 在我看来听起来相当糟糕。人们混淆了UserControl自定义控件的用法,这两个概念完全不同,旨在解决不同的使用情况。 - Federico Berasategui
显示剩余5条评论
1个回答

1
非常有趣的问题(至少对我来说),当您注册依赖属性时,实际上存在名称冲突。
我不确定这是否是一个答案,但如果您之前没有了解或考虑过这个问题,我认为您会发现这很有趣。
我使用了“CheckBox.IsChecked”,但任何唯一的名称都可能足够。
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
         "CheckBox.IsChecked",
         typeof(bool),
         typeof(CheckBox),
         new FrameworkPropertyMetadata(false,
                 FrameworkPropertyMetadataOptions.AffectsRender));

这将在不更改您的属性名称的情况下起作用。
public bool IsChecked
{
    get
    {
        return (bool)GetValue(IsCheckedProperty);
    }
    set
    {
        SetValue(IsCheckedProperty, value);
    }
}

当你为依赖属性创建名称时,必须选择独特的名称,这些名称在继承的任何基类中都没有被用于依赖属性或事件;否则,在运行时会抛出ArgumentException异常。有关依赖属性和活动绑定的更多信息,请参见Custom Activity Binding Sample和Simple Activity Sample。

https://msdn.microsoft.com/en-us/library/vstudio/ms734499(v=vs.90).aspx

又是一个提醒,我有多么菜鸟 :)

这解决了我的问题,尽管我似乎不满足冲突名称“用于您继承的任何基类中的依赖属性或事件”的标准。对于这个发现表示赞赏。 - Grault
是的,我尝试了所有的绑定类型,但都无法使其正常工作,除非更改名称或将属性变为普通属性而不是依赖属性。这个材料来自于 .net 3.5,没有更新版本(至少我没有找到),所以可能有所改变... - kirotab
不,谢谢你。因为我曾经遇到过一些依赖属性的问题,当时我称之为“黑魔法”,因为它们的行为看起来非常不合逻辑。现在,我至少有了一个新武器来尝试解决这些问题。 - kirotab
奇怪的是,当我在实际项目中实现时,它没有生效。看起来我需要提出一个新问题,为什么这并不总是有效。 - Grault
1
嗯,如果你把类名改成一个百分之百独特的名字,比如"asd",而不是"CheckBox.",如果还是不起作用,就取消选中答案,或许有人比我们聪明会解释。 - kirotab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接