通过RowDetail将DataGrid传递给ContentControl不能按预期工作

时间:2016-07-14 12:14:31

标签: c# wpf xaml datagrid user-controls

我需要的是UserControl能够列出与DataGrid类似的列表项,这意味着它将包含行列表,每行将有一个{ {1}}但它有一些附加功能。

我尝试过两种不同的场景。

场景1 - 无法重复使用但按预期工作:

MainWindow.xaml

RowDetail

MainWindow.xaml.cs

   <DataGrid ItemsSource="{Binding Employees}" >            
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid ItemsSource="{Binding Details}"/>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>

场景2 - 可以重复使用但不能按预期工作:

Mainwindow.xaml.cs

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var detail1 = new EmployeeDetails() {ManagerID=11, ManagerName="11 Name" , ManagerMobile = "123456" };
        var detail2 = new EmployeeDetails() { ManagerID = 12, ManagerName = "12 Name", ManagerMobile = "123456" };
        var detail3 = new EmployeeDetails() { ManagerID = 13, ManagerName = "13 Name", ManagerMobile = "123456" };

        var detail4 = new EmployeeDetails() { ManagerID = 11, ManagerName = "11 Name", ManagerMobile = "123456" };
        var detail5 = new EmployeeDetails() { ManagerID = 12, ManagerName = "12 Name", ManagerMobile = "123456" };
        var detail6 = new EmployeeDetails() { ManagerID = 13, ManagerName = "13 Name", ManagerMobile = "123456" };

        var detail7 = new EmployeeDetails() { ManagerID = 11, ManagerName = "11 Name", ManagerMobile = "123456" };
        var detail8 = new EmployeeDetails() { ManagerID = 12, ManagerName = "12 Name", ManagerMobile = "123456" };
        var detail9 = new EmployeeDetails() { ManagerID = 13, ManagerName = "13 Name", ManagerMobile = "123456" };

        var details1 = new List<EmployeeDetails>();
        details1.Add(detail1);
        details1.Add(detail2);
        details1.Add(detail3);

        var details2 = new List<EmployeeDetails>() {detail4, detail5, detail6};
        var details3 = new List<EmployeeDetails>() { detail7, detail8, detail9 };

        Employees = new List<Employee>();
        Employees.Add(new Employee() { ID = 1, Name = "Name1" , Details = details1 });
        Employees.Add(new Employee() { ID = 2, Name = "Name2", Details = details2 });
        Employees.Add(new Employee() { ID = 3, Name = "Name3", Details = details3 });

        this.DataContext = this;
    }

    public List<Employee> Employees { get; set; }

}

public class Employee
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<EmployeeDetails> Details { get; set; }
}

public class EmployeeDetails
{
    public int ManagerID { get; set; }
    public string ManagerName { get; set; }
    public string ManagerMobile { get; set; }

}

MainWindow.xaml.cs

   <local:CustomDataGrid ItemsSource="{Binding Employees}">            
        <local:CustomDataGrid.RowDetails>
            <DataGrid ItemsSource="{Binding Details}" />
        </local:CustomDataGrid.RowDetails>
    </local:CustomDataGrid>

CustomDataGrid.xaml

        --------------Same as Scenario 1-----------------

CustomDataGrid.xaml.cs

<Grid>
    <DataGrid x:Name="maingrid" AutoGenerateColumns="True" >
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding RowDetails, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>

</Grid>

我预计场景2的工作方式与场景1类似,但奇怪的是它不起作用。

Scenarion 2的问题是,/// <summary> /// Interaction logic for CustomDataGrid.xaml /// </summary> public partial class CustomDataGrid : UserControl { public CustomDataGrid() { InitializeComponent(); } public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource" , typeof(IList) , typeof(CustomDataGrid) , new PropertyMetadata(null, OnItemSourcechanged)); public IList ItemsSource { get { return (IList)GetValue(ItemsSourceProperty); } set { SetValue(ItemsSourceProperty, value); } } public static readonly DependencyProperty RowDetailsProperty = DependencyProperty.Register("RowDetails" , typeof(object) , typeof(CustomDataGrid)); private static void OnItemSourcechanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as CustomDataGrid).maingrid.ItemsSource = (IList)e.NewValue; } public object RowDetails { get { return GetValue(RowDetailsProperty); } set { SetValue(RowDetailsProperty, value); } } } 中的RowDetail在打开另一个DataGrid项后关闭后才会打开。

关于如何使场景2与场景1类似地工作的任何想法。

1 个答案:

答案 0 :(得分:1)

我会使用字符串来绑定details属性的名称......

<local:CustomDataGrid NewItemsSource="{Binding Employees}" CustomRowDetails="Details" />

使用自定义数据网格设置所选项目

<Grid>
    <DataGrid x:Name="maingrid" AutoGenerateColumns="True" ItemsSource="{Binding NewItemsSource}" SelectedItem="{Binding SelItem}" >
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid ItemsSource="{Binding MyDetails, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
</Grid>

通过反思

public partial class CustomDataGrid : UserControl, INotifyPropertyChanged
{
    public CustomDataGrid()
    {
        InitializeComponent();
        maingrid.DataContext = this;
    }

    public static readonly DependencyProperty NewItemsSourceProperty =
               DependencyProperty.Register("NewItemsSource"
                   , typeof(IEnumerable)
                   , typeof(CustomDataGrid)
                   , new PropertyMetadata(null, OnItemSourcechanged));



    public IEnumerable NewItemsSource
    {
        get { return (IEnumerable)GetValue(NewItemsSourceProperty); }
        set
        {
            SetValue(NewItemsSourceProperty, value);
        }
    }

    public static readonly DependencyProperty CustomRowDetailsProperty =
               DependencyProperty.Register("CustomRowDetails"
                   , typeof(string)
                   , typeof(CustomDataGrid));

    private static void OnItemSourcechanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as CustomDataGrid).maingrid.ItemsSource = (IEnumerable)e.NewValue;
    }

    public string CustomRowDetails
    {
        get
        {
            return (string)GetValue(CustomRowDetailsProperty);
        }
        set {
            SetValue(CustomRowDetailsProperty, value);
        }
    }

    private object selItem;

    public object SelItem
    {
        get { return selItem; }
        set {
            selItem = value;
            MyDetails = (IEnumerable<object>)value.GetType().GetProperty(CustomRowDetails).GetValue(value, null); ;
            OnPropertyChanged(() => SelItem);
            OnPropertyChanged(() => MyDetails);
        }
    }

    private IEnumerable<object> myDetails;

    public IEnumerable<object> MyDetails
    {
        get { return myDetails; }
        set { myDetails = value;
            OnPropertyChanged(() => MyDetails);
        }
    }



    #region INotifyPropertyChanged Members

    /// <summary>
    /// Raised when a property on this object has a new value.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;


    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }


    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {
        //this.VerifyPropertyName(propertyName);

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    #endregion // INotifyPropertyChanged Members

}