WPF:嵌套的DependencyProperties

时间:2011-05-06 06:33:00

标签: wpf data-binding user-controls binding dependency-properties

我在窗口上有一个OboutsableCollection“Layouts”和一个“SelectedLocation”DependencyProperty。 SelectedLocation有一个名为“Layout”的属性,它是一个包含“Name”等字段的对象。我正在尝试将一个组合框绑定到SelectedLayout但它不起作用。 以下不起作用,我尝试绑定到SelectedItem而无济于事。我相信这可能与我绑定到SelectedLocation DependencyProperty的subProperty这一事实有关(尽管这确实实现了INotifyPropertyChanged。

<ComboBox Grid.Row="2" Grid.Column="0" x:Name="cboLayout" ItemsSource="{Binding Layouts,ElementName=root}" SelectedValue="{Binding SelectedLocation.Layout.LayoutID,ElementName=root}" DisplayMemberPath="{Binding Name}" SelectedValuePath="LayoutID" />

但是,以下工作(也绑定到“SelectedLocation”DP:

<TextBox Grid.Row="4" Grid.Column="1" x:Name="txtName" Text="{Binding SelectedLocation.Name,ElementName=root,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

1 个答案:

答案 0 :(得分:1)

属性Layouts属于哪种类型?我想这样的事情:IEnumerable<Layout>。 但是您将所选值绑定到Layout.LayoutID。因此,当组合框包含Layout个对象时,您会遇到这种情况,并尝试通过Int标识符选择它。当然绑定引擎在那里找不到任何Int

我不知道你的代码的细节,所以我可以建议一件事:尝试减少你的绑定表达式:SelectedItem="{Binding SelectedLocation.Layout,ElementName=root}

如果没有成功,请提供更多代码以帮助我了解正在发生的事情。

<强> ==== UPDATE ====

正如我所说,你显然做错了什么。但我不是超自然主义者,无法猜出你失败的原因(没有你的代码)。如果您不想共享您的代码,我决定提供简单的示例,以证明一切正常。看看下面显示的代码,并告诉我你的应用程序有什么不同。

暴露属性LayoutId:

的类布局
public class Layout
{
    public Layout(string id)
    {
        this.LayoutId = id;
    }

    public string LayoutId
    {
        get;
        private set;
    }

    public override string ToString()
    {
        return string.Format("layout #{0}", this.LayoutId);
    }
}

Class SelectionLocation,它具有嵌套属性Layout:

public class SelectedLocation : INotifyPropertyChanged
{
    private Layout _layout;

    public Layout Layout
    {
        get
        {
            return this._layout;
        }
        set
        {
            this._layout = value;
            this.OnPropertyChanged("Layout");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        var safeEvent = this.PropertyChanged;
        if (safeEvent != null)
        {
            safeEvent(this, new PropertyChangedEventArgs(name));
        }
    }
}

带有依赖属性的Window类(实际上,在我的示例中,StartupView是UserControl,但没关系):

public partial class StartupView : UserControl
{
    public StartupView()
    {
        InitializeComponent();

        this.Layouts = new Layout[] { new Layout("AAA"), new Layout("BBB"), new Layout("CCC") };
        this.SelectedLocation = new SelectedLocation();
        this.SelectedLocation.Layout = this.Layouts.ElementAt(1);
    }

    public IEnumerable<Layout> Layouts
    {
        get
        {
            return (IEnumerable<Layout>)this.GetValue(StartupView.LayoutsProperty);
        }
        set
        {
            this.SetValue(StartupView.LayoutsProperty, value);
        }
    }

    public static readonly DependencyProperty LayoutsProperty =
        DependencyProperty.Register("Layouts",
            typeof(IEnumerable<Layout>),
            typeof(StartupView),
            new FrameworkPropertyMetadata(null));

    public SelectedLocation SelectedLocation
    {
        get
        {
            return (SelectedLocation)this.GetValue(StartupView.SelectedLocationProperty);
        }
        set
        {
            this.SetValue(StartupView.SelectedLocationProperty, value);
        }
    }

    public static readonly DependencyProperty SelectedLocationProperty =
        DependencyProperty.Register("SelectedLocation",
            typeof(SelectedLocation),
            typeof(StartupView),
            new FrameworkPropertyMetadata(null));
}

StartupView的XAML:

<UserControl x:Class="Test.StartupView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:self="clr-namespace:HandyCopy"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Name="Root">
    <WrapPanel>
        <ComboBox ItemsSource="{Binding Path=Layouts,ElementName=Root}"
                  SelectedItem="{Binding Path=SelectedLocation.Layout, ElementName=Root}"/>
    </WrapPanel>
</UserControl>