C# 将附加属性绑定到视图模型失败

C# 将附加属性绑定到视图模型失败,c#,.net,wpf,data-binding,attached-properties,C#,.net,Wpf,Data Binding,Attached Properties,我为ListBox创建了一个附加属性,如下所示: using ListBoxControl = System.Windows.Controls.ListBox; namespace App.Ui.Views.AttachedProperties { public class ListBox { public static readonly DependencyProperty autoScrollProperty = Dependency

我为ListBox创建了一个附加属性,如下所示:

using ListBoxControl = System.Windows.Controls.ListBox;

namespace App.Ui.Views.AttachedProperties
{
    public class ListBox
    {
        public static readonly DependencyProperty autoScrollProperty =
            DependencyProperty.RegisterAttached(
                "AutoScroll", 
                typeof(bool), 
                typeof(ListBoxControl), 
                new PropertyMetadata(false));

        public static void SetAutoScroll(ListBoxControl element, bool value)
        {
            element.SetValue(autoScrollProperty, value);
            if (value)
            {
                element.SelectionChanged += Element_SelectionChanged;
            }
            else
            {
                element.SelectionChanged -= Element_SelectionChanged;
            }
        }

        public static bool GetAutoScroll(ListBoxControl element)
        {
            return (bool)element.GetValue(autoScrollProperty);
        }

        private static void Element_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var listBox = (ListBoxControl)sender;
            listBox.ScrollIntoView(listBox.SelectedItem);
        }
    }
}
当我在xaml中使用静态真/假值时,它可以正常工作:

<ListBox ap:ListBox.AutoScroll="True">
    ...
</ListBox>

...
但如果我将数据绑定到视图模型中的属性:

<ListBox ap:ListBox.AutoScroll="{Binding Path=Settings.EnableAutoScroll}">
    ...
</ListBox>

...
然后我得到了以下异常:
无法在“ListBox”类型的“SetAutoScroll”属性上设置“Binding”。“绑定”只能在DependencyObject的DependencyProperty上设置。


这是可能的,还是我需要派生自己的自定义列表框来实现这一点?

这一行的问题
typeof(ListBoxControl)
。您应该指定自定义附加属性所在的类的名称

我建议将类从ListBox重命名为ListBoxExtensions,并使其成为静态的。这样就不必使用alias ListBoxControl
您的最终代码如下所示:

public static class ListBoxExtensions
{
    public static readonly DependencyProperty autoScrollProperty =
                DependencyProperty.RegisterAttached(
                    "AutoScroll", 
                    typeof(bool), 
                    typeof(ListBoxExtensions), 
                    new PropertyMetadata(false));

      ...
}
编辑: 好的,您的代码还有一个问题
从setter(
SetAutoScroll
)中删除侦听器的附件,并将此逻辑放入依赖项属性回调中

public static class ListBoxExtensions
{
    public static readonly DependencyProperty autoScrollProperty =
        DependencyProperty.RegisterAttached(
            "AutoScroll",
            typeof(bool),
            typeof(ListBoxExtensions),
            new PropertyMetadata(false, AutoScrollChangedCallback));

    public static void SetAutoScroll(ListBox element, bool value)
    {
        element.SetValue(autoScrollProperty, value);
    }

    public static bool GetAutoScroll(ListBox element)
    {
        return (bool)element.GetValue(autoScrollProperty);
    }

    private static void AutoScrollChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ListBox control = (ListBox)d;

        if ((bool)e.NewValue)
        {
            control.SelectionChanged += Element_SelectionChanged;
        }
        else
        {
            control.SelectionChanged -= Element_SelectionChanged;
        }
    }

    private static void Element_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var listBox = (ListBox)sender;
        listBox.ScrollIntoView(listBox.SelectedItem);
    }
}

ListBoxControl
System.Windows.Controls.Listbox
的别名。请参阅using语句。我的印象是,第二个类型参数是您附加到的依赖项对象的类型。键入注释时,您的编辑没有刷新。我来试一试。进行您建议的更改会使代码停止使用静态值。我很确定第二个类型参数是您将属性附加到的依赖对象的类型。自定义附加属性的要点是它们可以附加到任何元素。这使它们非常灵活。我更新了答案。应该有帮助。