开发者

WPF: Nested DependencyProperties

开发者 https://www.devze.com 2023-03-03 14:22 出处:网络
I have an ObservableCollection of \"Layouts\" and a \"SelectedLocation\" DependencyProperty on a Window. The SelectedLocation has a property called \"Layout\", which is an object containing fields lik

I have an ObservableCollection of "Layouts" and a "SelectedLocation" DependencyProperty on a Window. The SelectedLocation has a property called "Layout", which is an object containing fields like "Name" etc. I'm trying to bind a combobox to th开发者_StackOverflow社区e SelectedLayout but it's not working. The following does not work, I've tried binding to SelectedItem instead to no avail. I believe it may be something to do with the fact that I'm binding to a subProperty of the SelectedLocation DependencyProperty (though this does implement 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" />

However, the following works (Also bound to the "SelectedLocation" DP:

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


What type property Layouts has? I suppose something like this this: IEnumerable<Layout>. But you bind selected value to Layout.LayoutID. So you got situation, when combo box contains Layout objects, and you try to select it by Int identifier. Of course binding engine can't find any Int there.

I have no idea about details of your code, so one thing I could propose: try to reduce your binding expression: SelectedItem="{Binding SelectedLocation.Layout,ElementName=root}.

If no success, provide more code to help me understand what's going on.

====UPDATE====

As I've said, you are obviously doing something wrong. But I am not paranormalist and couldn't guess the reason of your fail (without your code). If you don't want to share your code, I decided to provide simple example in order to demonstrate that everything works. Have a look at code shown below and tell me what is different in your application.

Class Layout which exposes property 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 which has nested property 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));
        }
    }
}

And Window class with dependency properties (actually, in my example StartupView is UserControl, but it doesn't matter):

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));
}

XAML of StartupView:

<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>
0

精彩评论

暂无评论...
验证码 换一张
取 消