title: Best practices for WPF MVVM UserControls. Avoiding Binding problems
body: <p>I am trying to be a good soldier and design some simple User Controls for use in WPF MVVM applications.  I am trying (as much as possible) to make the UserControls themselves use MVVM, but I don't think the calling app should know that.  The calling app should just be able to slap down the user control, perhaps set one or two properties, and perhaps subscribe to events.  Just like when they use a regular control (ComboBox, TextBox, etc.)  I'm having a heck of a time getting the  bindings right.  Notice the use of ElementName in the below View.  This is instead of using DataContext.  Without further ado, here is my control:</p>
  
  <pre><code>&lt;UserControl x:Class="ControlsLibrary.RecordingListControl"
           ...
           x:Name="parent"
  
           d:DesignHeight="300" d:DesignWidth="300"&gt;
  &lt;Grid &gt;
      &lt;StackPanel Name="LayoutRoot"&gt;
      &lt;ListBox ItemsSource="{Binding ElementName=parent,Path=Recordings}" Height="100" Margin="5" &gt;
          &lt;ListBox.ItemTemplate&gt;
              &lt;DataTemplate&gt;
                  &lt;TextBlock Text="{Binding Path=FullDirectoryName}" /&gt;
              &lt;/DataTemplate&gt;
          &lt;/ListBox.ItemTemplate&gt;
      &lt;/ListBox&gt;
      &lt;/StackPanel&gt;
  
  &lt;/Grid&gt;
  </code></pre>
  
  <p></p>
  
  <p>In the code behind (if there is a way to avoid code behind, please tell me)...</p>
  
  <pre class="lang-cs prettyprint-override"><code>public partial class RecordingListControl : UserControl
  {
      private RecordingListViewModel vm = new RecordingListViewModel();
      public RecordingListControl()
      {
          InitializeComponent();
  
          // I have tried the next two lines at various times....
         // LayoutRoot.DataContext = vm;
          //DataContext = vm;
      }
  
  
      public static FrameworkPropertyMetadata md = new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPatientId));
      // Dependency property for PatientId
      public static readonly DependencyProperty PatientIdProperty =
     DependencyProperty.Register("PatientId", typeof(string), typeof(RecordingListControl), md);
  
      public string PatientId
      {
          get { return (string)GetValue(PatientIdProperty); }
          set { SetValue(PatientIdProperty, value);
          //vm.SetPatientId(value);
          }
      }
  
      // this appear to allow us to see if the dependency property is called.
      private static void OnPatientId(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
          RecordingListControl ctrl = (RecordingListControl)d;
          string temp = ctrl.PatientId;     
      }
  </code></pre>
  
  <p>In my ViewModel I have:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public class RecordingListViewModel : ViewModelBase
  {
      private ObservableCollection&lt;RecordingInfo&gt; _recordings = null;// = new ObservableCollection&lt;string&gt;();
      public RecordingListViewModel()
      {
  
      }
      public ObservableCollection&lt;RecordingInfo&gt; Recordings
      {
          get
          {
              return _recordings;
          }
      }
  
      public void SetPatientId(string patientId)
      {
          // bunch of stuff to fill in _recordings....
          OnPropertyChanged("Recordings");
      }
  
  }
  </code></pre>
  
  <p>I then put this control down in my main window and like so:</p>
  
  <pre><code>&lt;Grid&gt;
      &lt;ctrlLib:RecordingListControl  PatientId="{Binding PatientIdMain}" SessionId="{Binding SessionIdMain}" /&gt;
      &lt;Label Content="{Binding PatientIdMain}" /&gt; // just to show binding is working for non-controls
  &lt;/Grid&gt;
  </code></pre>
  
  <p>The error I get when I run all this is: </p>
  
  <pre><code>System.Windows.Data Error: 40 : BindingExpression path error: 'Recordings' property not found on 'object' ''RecordingListControl' (Name='parent')'. BindingExpression:Path=Recordings; DataItem='RecordingListControl' (Name='parent'); target element is 'ListBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
  </code></pre>
  
  <p>Clearly I have some sort of bindings problem.  This is actually much further than I was getting.  At least I'm hitting the code in the controls code behind:
  OnPatientId.</p>
  
  <p>Before, I didn't have the ElementName in the User Control and was using DataContext and was getting a binding error indicating that PatientIdMain was being considered a member of the user control.</p>
  
  <p>Can someone point me to an example of using a User Control with MVVM design in a MVVM application?  I would think this is a fairly common pattern. </p>
  
  <p>Let me know if I can provide more details.</p>
  
  <p>Many thanks,
  Dave</p>
  
  <p>Edit 1
  I tried har07's idea (see one of the answers).  I got:
  If I try:</p>
  
  <pre class="lang-cs prettyprint-override"><code>ItemsSource="{Binding ElementName=parent,Path=DataContext.Recordings}"
  </code></pre>
  
  <p>I get</p>
  
  <pre><code>System.Windows.Data Error: 40 : BindingExpression path error: 'Recordings' property not found on 'object' ''MainViewModel' (HashCode=59109011)'. BindingExpression:Path=DataContext.Recordings; DataItem='RecordingListControl' (Name='parent'); target element is 'ListBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
  </code></pre>
  
  <p>If I try:</p>
  
  <pre class="lang-cs prettyprint-override"><code>ItemsSource="{Binding Recordings}"
  </code></pre>
  
  <p>I get</p>
  
  <pre><code>System.Windows.Data Error: 40 : BindingExpression path error: 'Recordings' property not found on 'object' ''MainViewModel' (HashCode=59109011)'. BindingExpression:Path=Recordings; DataItem='MainViewModel' (HashCode=59109011); target element is 'ListBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
  </code></pre>
  
  <p>I think his first idea (and maybe his second) are very close, but recall, Recordings is defined in the ViewModel, not the view.  somehow I need to tell XAML to use viewModel as source.  That's what setting the DataContext does, but as I said in the main part, that creates problems elsewhere (you get binding errors related to binding from the MainWindown to properties on the control).</p>
  
  <p>Edit 2.  If I try har07's first suggestion:</p>
  
  <pre class="lang-cs prettyprint-override"><code>ItemsSource="{Binding ElementName=parent,Path=DataContext.Recordings}"
  </code></pre>
  
  <p>AND add in the code behind for the control:</p>
  
  <pre class="lang-cs prettyprint-override"><code>RecordingListViewModel vm = new RecordingListViewModel();
  DataContext = vm;
  </code></pre>
  
  <p>I get:</p>
  
  <pre><code>System.Windows.Data Error: 40 : BindingExpression path error: 'PatientIdMain' property not found on 'object' ''RecordingListViewModel' (HashCode=33515363)'. BindingExpression:Path=PatientIdMain; DataItem='RecordingListViewModel' (HashCode=33515363); target element is 'RecordingListControl' (Name='parent'); target property is 'PatientId' (type 'String')
  </code></pre>
  
  <p>in other words, the control seems fine, but the binding of the dependency proprerties to the  main window seem messed up.  The compiler assumes that PatientIdMain is part of RecordingListViewModel.<br>
  Various posts indicated that I couldn't set DataContext for this very reason.  It would mess up bindings to the main window.  See for example:
  <a href="https://stackoverflow.com/questions/6787219/binding-to-a-dependency-property-of-a-user-control-wpf-xaml">Binding to a dependency property of a user control WPF/XAML</a> and check out Marc's answer.</p>