15
votes

My app looks like this:


SectionHeader

SectionHeader

Content

SectionHeader

Content


SectionHeader is a user control with two dependency properties = Title and Apps.

Title does not change but Apps needs to be bound to the main window view model Apps property. The Apps property is only required for two of the three section headers.

<c:SectionHeader DockPanel.Dock="Top" x:Name="SectionResources" Title="RESOURCES"
   Apps="{Binding Path=Apps}" />

This is how it is at the moment. The problem is that the Apps don't show up.

In SectionHeader the DataContext is set to itself as follows which allows the Title to show up.

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Apps is the ItemsSource for a ItemsControl in the UserControl:

<ItemsControl
      ItemsSource="{Binding Apps}">

So my questions are:

  • How can I data bind to a UserControl DP?
  • Is their an easier way of doing this layout without UserControls?

EDIT:

Forgot to mention that Apps is an ObservableCollection of AppsItems.

This is what my DP looks like:

public static readonly DependencyProperty AppsProperty = DependencyProperty.Register("Apps",
  typeof (ObservableCollection<AppsItem>), typeof (SectionHeader),
  new PropertyMetadata(null, OnAppsPropertyChanged));

private static void OnAppsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  Console.WriteLine("Hello!!!");
  var sectionHeader = d as SectionHeader;
  var value = e.NewValue as ObservableCollection<AppsItem>;
  sectionHeader.Apps = value;
}
4

4 Answers

23
votes

Give a name to your usecontrol and try binding like this

ItemsSource="{Binding Apps,ElementName=root}"

and root is the name give to your usercontrol

  <UserControl x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Height="350" Width="525"
     x:Name="root">

it is element binding to user control which has Apps property

11
votes

Having tried to repro this from your description and coming across a similar problem I found that the only way I could make it work is to not set the DataContext of the UserControl, and instead use ElementBinding:

<UserControl x:Class="WpfApplication2.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             x:Name="thisUC"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Border Background="Red" Padding="10">
        <ListBox x:Name="ucList" ItemsSource="{Binding ElementName=thisUC, Path=UCApps}"/>
        </Border>

    </Grid>
</UserControl>

The implementation of this UC is trivially simple:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Collections;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public IEnumerable UCApps
        {
            get { return (IEnumerable)GetValue(UCAppsProperty); }
            set { SetValue(UCAppsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Apps.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCAppsProperty =
            DependencyProperty.Register("UCApps", typeof(IEnumerable), typeof(UserControl1), new UIPropertyMetadata(null));

        public UserControl1()
        {
            InitializeComponent();            
        }
    }
}

as is the XAML that calls it:

<Grid >
    <my:UserControl1 x:Name="ucName" UCApps="{Binding Path=Apps}"/>
</Grid>

(I changed the name of Apps in your Usercontrol to UCApps so I could see what was going on - too many properties with the same name got confusing!)

3
votes
Apps="{Binding Path=Apps}"

Binds Apps to itself.

Try following

1) Your ViewModel should be a DataContext of Control, then you can use following

Apps="{Binding DataContext.Apps}"

Also you can use Snoop utility to find binding issues in real time

1
votes

Have you tried

Apps="{Binding Apps}" 

instead of

Apps="{Binding Path=Apps}"

in your top level control?

Also, do you get any binding errors in the VS output window when you run the app?