PitAttack76
PitAttack76

Reputation: 2220

Loading UserControl to ItemsControl with MVVM

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

Upvotes: 3

Views: 6579

Answers (3)

user303754
user303754

Reputation: 569

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.

Upvotes: 0

Rachel
Rachel

Reputation: 132548

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

Upvotes: 6

Arthur Nunes
Arthur Nunes

Reputation: 7048

Change :

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

To:

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

Upvotes: 0

Related Questions