3

I have a UserControl which I would like to load multiple times on my MainWindow. For this I use an ItemsControl:

    <ItemsControl Grid.Row="1"
              ItemsSource="{Binding FtpControlList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <WrapPanel Orientation="Horizontal"
                 IsItemsHost="True" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type my:BackUpControl}">
      <my:BackUpControl Margin="5"
                        Width="500" />
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

My UserControl is bound by a ViewModel. My MainWindow also has a ViewModel. In the MainWindowViewModel I have an OberservableCollection dependency property which houlds a list of my UserControlViewModels. In the constructor of the MainWindowViewModel I add some UserControlViewModels to the List.

    public MainWindowViewModel()
{
  FtpControlList = new ObservableCollection<BackUpControlViewModel>();
  FtpControlList.Add(new BackUpControlViewModel("View 1"));
  FtpControlList.Add(new BackUpControlViewModel("View 2"));
  FtpControlList.Add(new BackUpControlViewModel("View 3"));
}

public static readonly DependencyProperty FtpControlListProperty = DependencyProperty.Register("FtpControlList", typeof(ObservableCollection<BackUpControlViewModel>), typeof(MainWindowViewModel));
public ObservableCollection<BackUpControlViewModel> FtpControlList
{
  get { return (ObservableCollection<BackUpControlViewModel>)GetValue(FtpControlListProperty); }
  set { SetValue(FtpControlListProperty, value); }
}

Now for some reason it loads 3 times an empty usercontrol and NOT the ones in the FtpControlList property withe the property set to 'View 1, View 2 and View 3'. How can I make sure that the UserControls from the list are loaded and not empty ones?

Part of the UserControlViewModel:

    // part of the UserControl Viewmodel
    public BackUpControlViewModel()
{
}

public BackUpControlViewModel(string header)
{
  GroupBoxHeader = header;
}

    #region Dependency Properties
public static readonly DependencyProperty GroupBoxHeaderProperty = DependencyProperty.Register("GroupBoxHeader", typeof(string), typeof(BackUpControlViewModel), new UIPropertyMetadata("empty"));
public string GroupBoxHeader
{
  get { return (string)GetValue(GroupBoxHeaderProperty); }
  set { SetValue(GroupBoxHeaderProperty, value); }
}

public static readonly DependencyProperty FtpUrlProperty = DependencyProperty.Register("FtpUrl", typeof(string), typeof(BackUpControlViewModel), new UIPropertyMetadata("ftpurl"));
public string FtpUrl
{
  get { return (string)GetValue(FtpUrlProperty); }
  set { SetValue(FtpUrlProperty, value); }
}

public static readonly DependencyProperty FtpUserProperty = DependencyProperty.Register("FtpUser", typeof(string), typeof(BackUpControlViewModel), new UIPropertyMetadata("ftpUser"));
public string FtpUser
{
  get { return (string)GetValue(FtpUserProperty); }
  set { SetValue(FtpUserProperty, value); }
}
#endregion

It will probably be something stupid but I can't seem to find it. The datacontext for MainWindow and the UserControl are bound to it's Viewmodel.

EDIT: BackupControl datacontext set to BackupControlViewModel (to answer Rachel's question)

   public partial class BackUpControl : UserControl
  {
    public BackUpControl()
    {
      InitializeComponent();
      this.DataContext = new BackUpControlViewModel();
    }
  }
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
PitAttack76
  • 2,120
  • 5
  • 31
  • 44
  • Is `BackUpControlViewModel` actually a `UserControl`? Or do you set the `DataContext` anywhere in the UserControl `my:BackUpControl`? Based on your code provided, WPF should load you three blank `my:BackUpControl` objects, with the `DataContext` behind those objects bound to the `BackUpControlViewModel` – Rachel Dec 12 '12 at 16:50
  • @Rachel. I've edited my post and added the datacontext setting for the BackupUserControl. What you say is correct, it loads me 3 blank usercontrols. But why doesn't it load my 3 usercontrol viewmodels I add to FtpControlList in the MainViewModel? See public MainWindowViewModel() { FtpControlList = new ObservableCollection(); FtpControlList.Add(new BackUpControlViewModel("View 1")); FtpControlList.Add(new BackUpControlViewModel("View 2")); FtpControlList.Add(new BackUpControlViewModel("View 3")); } – PitAttack76 Dec 12 '12 at 19:13

3 Answers3

6

You are overwriting the DataContext of your UserControl by setting it in the constructor of your UserControl after calling InitializeComponent();

By default, the ItemsControl will create an ItemTemplate for each item in the collection, and set it's DataContext to the item from the ItemsSource. The end result will be three new my:BackUpControl objects, with the DataContext behind those objects bound to the BackUpControlViewModel from ItemsControl.ItemsSource

Remove the line this.DataContext = new BackUpControlViewModel(); from your UserControl's constructor, and it should work like you expect

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Thx, that did it. I knew it was something with the binding but couldn't see what.. It gets me confused sometimes :) You're great! – PitAttack76 Dec 12 '12 at 23:01
0

The issue might be that your viewmodel has dependency properties. Normally you would just make your viewmodel implement INotifyPropertyChanged and the properties would be regular (not dependency properties). Unless you have a specific requirement for them to be DPs I'd switch them over.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
user303754
  • 459
  • 3
  • 11
  • Nope, that's not it. I changed the GroupBoxHeader proprty to a NotifyChanged property but the result is the same.. – PitAttack76 Dec 12 '12 at 16:20
  • are there any binding errors in your output? Something along the lines of 'Binding error: Property blah doesn't exist...' – user303754 Dec 12 '12 at 16:26
  • Yeah indeed, following error for all my properties: System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=GroupBoxHeader; DataItem=null; target element is 'GroupBox' (Name='groupBox1'); target property is 'Header' (type 'Object') But how to fix this? I must do something wrong with the binding. – PitAttack76 Dec 12 '12 at 16:40
0

Change :

<DataTemplate DataType="{x:Type my:BackUpControl}">

To:

<DataTemplate DataType="{x:Type my:BackUpControlViewModel}">
Arthur Nunes
  • 6,718
  • 7
  • 33
  • 46
  • Doesn't work, still loads 3 empty usercontrol viewmodels and not the ones I add to the FtpControlList on the MainWindowViewModel.. – PitAttack76 Dec 12 '12 at 19:14
  • Does it at least load BackUpControl instances? You need to identify if the problem is the template not being applied or if some bindings in your BackUpControls are not being evaluated correctly. In the later we need to check your BackUpControl xaml to check how it is supposed to look. – Arthur Nunes Dec 12 '12 at 19:45