1

DI'm trying to expose the DataGrid.Columns property to the Ancestor UserControl like I did with the items source using the answer here. There doens't seem to be any properties available for me to bind the DataColumns in the following fashion:

<PagedDataGrid>
    <PagedDataGrid.Columns>
        <DataGridTextColumn Header="Custom Column"/>
    <PagedDataGrid.Columns>
</PagedDataGrid>

Here's what I have so far. Do I need to do this in the code behind somehow?

XAML:

<UserControl x:Class="WpfPagedGrid.PagedDataGrid"
         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" 
         xmlns:local="clr-namespace:WpfPagedGrid" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <WrapPanel><TextBlock>Paging Controls...</TextBlock></WrapPanel>
        <DataGrid Name="dataGrid" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
                                AncestorType=local:PagedDataGrid, AncestorLevel=1}, Path=ItemsSource}">
        </DataGrid>
    </Grid>
</UserControl>

C#:

namespace WpfPagedGrid {
    public partial class PagedDataGrid : UserControl {
        public PagedDataGrid() { InitializeComponent(); }

        public IEnumerable ItemsSource {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty = DataGrid.ItemsSourceProperty.AddOwner(typeof(PagedDataGrid));

        //Does not work as there is no DataGrid.Columns property...
        //public ObservableCollection<DataGridColumn> Columns {
            //get { return (ObservableCollection<DataGridColumn>)GetValue(ColumnsProperty); }
            //set { SetValue(ItemsSourceProperty, value); }
        //}

        //public static readonly DependencyProperty ColumnsProperty = DataGrid.CloumnsProperty.AddOwner(typeof(PagedDataGrid));
    }
}

Edit: To clarify, I'm trying to specify columns on the user control and bind the DataGrid to those.

Community
  • 1
  • 1
Rex NFX
  • 443
  • 5
  • 11
  • Are you trying to specify columns on the user control and bind the DataGrid to those? Or are you trying to make the user control aware of what columns the DataGrid has? – NextInLine Feb 13 '15 at 18:10
  • I'm trying to specify columns on the user control and bind the DataGrid to those. – Rex NFX Feb 13 '15 at 18:14

1 Answers1

2

Since DataGrid.Columns is a read-only collection, it cannot be directly bound. Instead, you can get this through what's often called an attached behavior. Basically:

  • create an class with an attached property of type ObservableCollection
  • bind this class to your collection on the UserControl, and attach it to the DataGrid
  • in the On[Property]Changed handler for the attached property, your sender will be the DataGrid instance and the collection being passed in will be your columns. You can then set the DataGrid columns.

So in code:

<DataGrid Name="dataGrid" ...
    MyColumnHelper.Columns="{Binding RelativeSource={RelativeSource FindAncestor,
    AncestorType=local:PagedDataGrid, AncestorLevel=1}, Path=MyColumns}" />

And for the handler:

OnMyColumnHelperColumnsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
    DataGrid.Columns.Clear();
    foreach(var column in (IEnumerable)args.NewValue)
    {
        DataGrid.Columns.Add(column);
    }
}

A word of warning - the code above is written for something where the underlying collection on your user control creates a new collection each time it wants to add or remove columns. While you can use an ObservableCollection, you run into complexities:

  • You have to subscribe to its CollectionChanged event in the event handler above
  • You then have to use weak events, or subscribe to the DataGrid.Unloaded event as well, so that you can unsubscribe from CollectionChanged and prevent memory leaks (this would be an issue the lifetime of your user control is longer than that of your data grid, or if your data grid was ever unloaded and reloaded into the visual tree)
NextInLine
  • 2,126
  • 14
  • 23