简体   繁体   中英

WPF DataGrid - Bind DataContext through custom property in parent UserControl

I`m writing a new control containing three DataGrid's (DG_Top, DG_Center, DG_Bottom).

When trying to set the data for this control nothing happens. The ContextProperties (see below) are filled, but the data is not displayed.

In the UserControl (XGrid) I`ve created some properties to manage the DataBindings:

    public static readonly DependencyProperty ItemsSource_TopProperty = DependencyProperty.Register("ItemsSource_Top", typeof(IEnumerable), typeof(XGrid));
    public static readonly DependencyProperty ItemsSource_CenterProperty = DependencyProperty.Register("ItemsSource_Center", typeof(IEnumerable), typeof(XGrid));
    public static readonly DependencyProperty ItemsSource_BottomProperty = DependencyProperty.Register("ItemsSource_Bottom", typeof(IEnumerable), typeof(XGrid));
    public static readonly DependencyProperty DataContext_TopProperty = DependencyProperty.Register("DataContext_Top", typeof(object), typeof(XGrid));
    public static readonly DependencyProperty DataContext_CenterProperty = DependencyProperty.Register("DataContext_Center", typeof(object), typeof(XGrid));
    public static readonly DependencyProperty DataContext_BottomProperty = DependencyProperty.Register("DataContext_Bottom", typeof(object), typeof(XGrid));


    public IEnumerable ItemsSource_Top
    {
        get { return (IEnumerable)GetValue(ItemsSource_TopProperty); }
        set
        {
            SetValue(ItemsSource_TopProperty, value);
            OnPropertyChanged();
        }
    }
    public IEnumerable ItemsSource_Center...
    public IEnumerable ItemsSource_Bottom...

    public object DataContext_Top
    {
        get { return (object)GetValue(DataContext_TopProperty); }
        set
        {
            SetValue(DataContext_TopProperty, value);
            OnPropertyChanged();
        }
    }

    public object DataContext_Center...
    public object DataContext_Bottom...

The binding in the XGrid.xaml is the following:

    <UserControl x:Class="WPF.XGrid"
         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" 
         mc:Ignorable="d" 
         x:Name="control">
 <StackPanel>
    <DataGrid ItemsSource="{Binding ItemsSource_Top, ElementName=control}"
              DataContext="{Binding DataContext_Top, ElementName=control}"  
...

I´m using the XGrid control as follows (in xaml):

<iw:XGrid x:Name="XG_Test" ItemsSource_Center="{Binding}"  />

And in the .cs file:

DataTable dt = new DataTable();
dt.Columns.Add("TEST");
dt.Rows.Add(new string[] { "" });
XG_Test.DataContext_Center = dt.DefaultView;

Can anybody tell me why the binding isn't working? THANKS!


-------EDIT 1-------

Visual Studio Output doesn't say anything about an error

这就是snoop对内部DataGrid(DG_Center)所说的

Ok, I think I know where the problem is. Your DataGrid's ItemsSource Binding is not taking into account the DataGrid DataContext, but is instead searching for its value in the XGrid control's DataContext.

You have to make sure you're using the DataContext you want, doing something like this:

<iw:XGrid x:Name="XG_Test" 
          ItemsSource_Center="{Binding DataContext_Center.DefaultView,
                                       RelativeSource={RelativeSource Mode=Self}}"  />

But this kinda defeats the purpose of what you were trying to achieve, I guess...

EDIT: I've found another way that could make your original Bindings work as intended. It requires that you modify the UserControl's code-behind and create the ItemsSource bindings from there instead of doing it from XAML.

I'll take the "top" DataGrid as example.

  • First of all, give names to the DataGrids inside your UserControl, and remove the ItemsSource binding:

     <DataGrid x:Name="DataGrid_Top" DataContext="{Binding DataContext_Top, ElementName=control}" ... /> 
  • Then, declare a property changed callback for your ItemsSource DependencyProperties:

     public static readonly DependencyProperty ItemsSource_TopProperty = DependencyProperty.Register("ItemsSource_Top", typeof(IEnumerable), typeof(XGrid), new PropertyMetadata(null, OnItemsSource_TopPropertyChanged)); 
  • In that callback you'll create the Binding, but in a different than usual way...

     private static void OnItemsSource_TopPropertyChanged(object sender, DependencyPropertyChangedEventArgs e) { var control = sender as XGrid; var binding = BindingOperations.GetBindingBase(control, XGrid.ItemsSource_TopProperty); DataGrid_Top.SetBinding(DataGrid.ItemsSourceProperty, binding); } 

And that's it... You're kinda "copying" the Binding from the DependencyProperty and into the ItemsSource property.

You can then change the XAML again to your original example, and it should work.

<iw:XGrid x:Name="XG_Test" ItemsSource_Center="{Binding}"  />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM