Results 1 to 5 of 5

Thread: [WPF] DataGrid in UserControl - binding the ItemsSource on the containing Window

Threaded View

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    [WPF] DataGrid in UserControl - binding the ItemsSource on the containing Window

    Hi,

    I have a UserControl 'TestUserControl' that contains a DataGrid amongst other things. On my MainWindow I now have several of these UserControls (in different TabItems) and each of the grids in the UserControls have to bind to a different set of data. I want to control this binding in the MainWindow.

    The idea is basically this:
    xml Code:
    1. <TabControl>
    2.             <TabItem Header="Addresses">
    3.                 <my:TestUserControl GridItems="{Binding Addresses}" />
    4.             </TabItem>
    5.             <TabItem Header="Phone numbers">
    6.                 <my:TestUserControl GridItems="{Binding PhoneNumbers}" />
    7.             </TabItem>
    8.             <TabItem Header="Websites">
    9.                 <my:TestUserControl GridItems="{Binding Websites}" />
    10.             </TabItem>
    11.         </TabControl>


    For testing purposes I've simplified it a bit: a single TestUserControl on the MainWindow that binds to a single List<GridItem>, where GridItem is a simple test class:
    csharp Code:
    1. public class GridItem : NotifyObject
    2.     {
    3.         private int _Id;
    4.         public int Id
    5.         {
    6.             get { return _Id; }
    7.             set
    8.             {
    9.                 _Id = value;
    10.                 this.OnPropertyChanged(() => this.Id);
    11.             }
    12.         }
    13.  
    14.         private string _Name;
    15.         public string Name
    16.         {
    17.             get { return _Name; }
    18.             set
    19.             {
    20.                 _Name = value;
    21.                 this.OnPropertyChanged(() => this.Name);
    22.             }
    23.         }
    24.     }
    (NotifyObject is just a base class implementing INotifyPropertyChanged which easily handles raising the PropertyChanged event)

    The MainWindow has this XAML code:
    xml Code:
    1. <Window x:Class="UserControlGridTest.MainWindow"
    2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4.         xmlns:my="clr-namespace:UserControlGridTest"
    5.         Title="MainWindow" Height="350" Width="525">
    6.     <Grid>
    7.         <my:TestUserControl GridItems="{Binding TestItems}" />
    8.     </Grid>
    9. </Window>
    It's DataContext is set to the following ViewModel:
    csharp Code:
    1. public class MainViewModel
    2.     {
    3.         public MainViewModel()
    4.         {
    5.             _TestItems = new List<GridItem>
    6.                            {
    7.                                new GridItem {Id = 1, Name = "Item 1"},
    8.                                new GridItem {Id = 2, Name = "Item 2"},
    9.                                new GridItem {Id = 3, Name = "Item 3"},
    10.                                new GridItem {Id = 4, Name = "Item 4"},
    11.                            };
    12.         }
    13.  
    14.         private List<GridItem> _TestItems;
    15.         public List<GridItem> TestItems
    16.         {
    17.             get
    18.             {
    19.                 return _TestItems;
    20.             }
    21.         }
    22.     }

    The code for the TestUserControl is this:
    xml Code:
    1. <UserControl x:Class="UserControlGridTest.TestUserControl"
    2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6.              mc:Ignorable="d"
    7.              d:DesignHeight="300" d:DesignWidth="300">
    8.     <Grid>
    9.         <Grid.RowDefinitions>
    10.             <RowDefinition Height="Auto" />
    11.             <RowDefinition Height="*" />
    12.         </Grid.RowDefinitions>
    13.        
    14.         <TextBlock Text="Items:" Grid.Row="0" Margin="5"/>
    15.         <DataGrid ItemsSource="{Binding GridItems}" Grid.Row="1" Margin="5" AutoGenerateColumns="true" />
    16.     </Grid>
    17. </UserControl>
    csharp Code:
    1. public partial class TestUserControl : UserControl
    2.     {
    3.         private readonly TestUserControlViewModel viewModel;
    4.  
    5.         public TestUserControl()
    6.         {
    7.             InitializeComponent();
    8.  
    9.             viewModel = new TestUserControlViewModel(this);
    10.             this.DataContext = viewModel;
    11.         }
    12.  
    13.         public static DependencyProperty ItemsProperty =
    14.             DependencyProperty.Register("GridItems", typeof (List<GridItem>), typeof (TestUserControl));
    15.  
    16.         public List<GridItem> GridItems
    17.         {
    18.             get { return (List<GridItem>) GetValue(ItemsProperty); }
    19.             set { SetValue(ItemsProperty, value); }
    20.         }
    21.     }

    The DataGrid binds to the GridItems property on the ViewModel, which in turn returns the DependencyProperty in the TestUserControl:
    csharp Code:
    1. public class TestUserControlViewModel
    2.     {
    3.         private readonly TestUserControl _Control;
    4.  
    5.         public TestUserControlViewModel(TestUserControl control)
    6.         {
    7.             _Control = control;
    8.         }
    9.  
    10.         public List<GridItem> GridItems
    11.         {
    12.             get { return _Control.GridItems; }
    13.         }
    14.     }

    As far as I can see, this should work. In the MainWindow, the GridItems property of the TestUserControl is bound to the list of items. This GridItems property is a DependencyProperty (otherwise I cannot bind to it?). The DataGrid on the TestUserControl in turn binds to the GridItems property of its own ViewModel, which returns the value of the DependencyProperty (which should be set to the list of test items).

    Yet, the grid remains empty. There's no errors or warnings, just nothing seems to happen...

    What am I doing wrong?

    Thanks!


    Edit:
    As a bonus, I know I'm horribly breaking the MVVM pattern here by letting the TestUserControlViewModel have a reference to the TestUserControl, but I don't see how else I'm going to achieve what I want... Any idea's?

    The only other option I can see is to get rid of the UserControl altogether and just putting the grids on the MainWindow directly. But that doesn't seem like a very good solution, for one because it's a lot of repeated XAML and second because a lot more will be going on later, such as a toolbar for Add/Edit/Delete buttons and such. That's a LOT of repeated code that would fit very nicely into a single UserControl...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width