在内置的WPF DataGrid中,我可以为DataGridTemplateColumn设置数据源吗? [英] In the built-in WPF DataGrid, can I set the datasource for a DataGridTemplateColumn?

查看:198
本文介绍了在内置的WPF DataGrid中,我可以为DataGridTemplateColumn设置数据源吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这个假设的例子中,想象一下,我有一个FooSet对象,它有五个属性Foo1,Foo2,Foo3 Foo4和Foo5,它们都是Foo类型,它们本身有几个属性。最后,我有一个名为FooTemplate的DataTemplate,它以图形的方式知道如何显示Foo类型的对象。



现在,当使用内置的DataGrid时,ItemsSource是一个集合的FooSet对象。我想做的是设置五个模板列,全部使用FooTemplate数据模板。但是,DataGrid的模板列类型不允许我设置该列的数据源(例如Foo1,Foo2等),所以我最终重复模板,每一列一次,只需将Foo1.SomeProp更改为Foo2.SomeProp在模板的绑定当中,这是荒谬的。但是,对于我来说,我的生活找不到如何说列B使用Foo2作为数据源。



这里有一些伪XAML来显示我想要的...

 <资源> 
< DataTemplate TargetType =Foo>
< StackPanel>
< local:FooPropAControl Value ={Binding FooPropA}/>
< local:FooPropBControl Value ={Binding FooPropB}/>
< local:FooPropCControl Value ={Binding FooPropC}/>
< / StackPanel>
< / DataTemplate>
< / Resources>

< DataGrid ItemsSource ={Binding MyItems}AutoGenerateColumns =false>
< DataGrid.Columns>
< DataGridTemplateColumn DataSource ={Binding Foo1}/>
< DataGridTemplateColumn DataSource ={Binding Foo2}/>
< DataGridTemplateColumn DataSource ={Binding Foo3}/>
< DataGridTemplateColumn DataSource ={Binding Foo4}/>
&DataGridTemplateColumn DataSource ={Binding Foo5}/>
< /DataGrid.Columns>
< / DataGrid>

即使我必须在列中明确指定模板,这还是很好的。它将该列的数据源设置为FooSet的属性,因此我可以使用一个DataTemplate。所有其他列允许您设置一些绑定。我甚至尝试将DataGridTemplateColumn子类化以添加DataSource,但没有太远(我的猜测是因为本身没有列,而是指示行中的单元格如何生成,但这只是一个猜测。)



现在我知道第三方Xceed网格可以让您明确指定,但我希望能够获得本地解决方案。



那么,howzyadoodat?或者你可以吗?



M

解决方案

使用 ContentControl 来处理它,代码仍然会有点膨胀,但它比复制整个模板更好,例如:

 < DataGrid ItemsSource ={Binding EmpSets}> 
< DataGrid.Resources>
< DataTemplate DataType ={x:Type obj:Employee}>
< TextBlock>
< Run Text ={Binding Name}/>
< Run Name =RunChanText = - />
< Run Text ={Binding Occupation}/>
< / TextBlock>
< / DataTemplate>
< /DataGrid.Resources>
< DataGrid.Columns>
< DataGridTemplateColumn Header =Emp1>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< ContentControl Content ={Binding Emp1}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< / DataGridTemplateColumn>
< DataGridTemplateColumn Header =Emp2>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< ContentControl Content ={Binding Emp2}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< / DataGridTemplateColumn>
<! - ... - >
< /DataGrid.Columns>
< / DataGrid>

这里我在资源中使用一个隐式的DataTemplate,但您也可以将其明确应用于 ContentTemplate 通过定义&引用一个键,但是你知道。






Barebone子类化方法:

  public class DataGridTemplateMemberColumn:DataGridTemplateColumn 
{
public static readonly DependencyProperty MemberPathProperty =
DependencyProperty.Register(MemberPath,typeof(string) typeof(DataGridTemplateMemberColumn),新的UIPropertyMetadata(null));
public string MemberPath
{
get {return(string)GetValue(MemberPathProperty); }
set {SetValue(MemberPathProperty,value);


protected override System.Windows.FrameworkElement GenerateEditingElement(DataGridCell cell,object dataItem)
{
return GenerateContent(CellEditingTemplate,dataItem);
}

protected override System.Windows.FrameworkElement GenerateElement(DataGridCell cell,object dataItem)
{
return GenerateContent(CellTemplate,dataItem);
}

private FrameworkElement GenerateContent(DataTemplate template,object dataItem)
{
var contentControl = new ContentControl();
contentControl.ContentTemplate = template;
if(MemberPath!= null)
{
Binding binding = new Binding(MemberPath);
binding.Source = dataItem;
contentControl.SetBinding(ContentControl.ContentProperty,binding);
}
else
{
contentControl.Content = dataItem;
}
return contentControl;
}
}





 < DataGrid.Columns> 
< cex:DataGridTemplateMemberColumn MemberPath =Emp1/>
< cex:DataGridTemplateMemberColumn MemberPath =Emp2/>
< cex:DataGridTemplateMemberColumn MemberPath =Emp3/>
< cex:DataGridTemplateMemberColumn MemberPath =Emp4/>
< cex:DataGridTemplateMemberColumn MemberPath =Emp5/>
< /DataGrid.Columns>


In this hypothetical example, imagine I have an object FooSet that has five properties Foo1, Foo2, Foo3 Foo4 and Foo5 all of which are type Foo which itself has several properties. Finally, I have a DataTemplate called FooTemplate that knows how to display objects of type Foo in a graphical way.

Now when using the built-in DataGrid, ItemsSource is a collection of FooSet objects. What I want to do is set up five templated columns that all use the FooTemplate data template. However, the DataGrid's template column type doesn't let me set the data source for that column (e.g. Foo1, Foo2, etc.) so I end up duplicating the template, once for each column, just changing Foo1.SomeProp to Foo2.SomeProp in the template's bindings, which is ridiculous of course. But I for the life of me can't find how to say 'Column B uses Foo2 as it's data source.'

Here's some Pseudo-XAML to show what I want...

<Resources>
    <DataTemplate TargetType="Foo">
        <StackPanel>
            <local:FooPropAControl Value="{Binding FooPropA}" />
            <local:FooPropBControl Value="{Binding FooPropB}" />
            <local:FooPropCControl Value="{Binding FooPropC}" />
        </StackPanel>
    </DataTemplate>
</Resources>

<DataGrid ItemsSource="{Binding MyItems}" AutoGenerateColumns="false">
    <DataGrid.Columns>
        <DataGridTemplateColumn DataSource="{Binding Foo1}" />
        <DataGridTemplateColumn DataSource="{Binding Foo2}" />
        <DataGridTemplateColumn DataSource="{Binding Foo3}" />
        <DataGridTemplateColumn DataSource="{Binding Foo4}" />
        <DataGridTemplateColumn DataSource="{Binding Foo5}" />
    </DataGrid.Columns>
</DataGrid>

Even if I have to explicitly specify the template in the column, that's still fine. It's setting the data source for that column to a property of FooSet so I can just use one DataTemplate. All the other columns let you set some binding that does that. I even tried subclassing DataGridTemplateColumn to add DataSource but didn't get too far (my guess is because there isn't a column per se but rather that dictates how cells in rows are generated, but that's just a guess.)

Now I know the 3rd-party Xceed grid lets you specify exactly that but I'm hoping for a native solution.

So, howzyadoodat? Or can you?

M

解决方案

Good question, i would approach it using a ContentControl, the code will still be a bit inflated but it's better than duplicating the whole template, e.g.:

<DataGrid ItemsSource="{Binding EmpSets}">
    <DataGrid.Resources>
        <DataTemplate DataType="{x:Type obj:Employee}">
            <TextBlock>
                <Run Text="{Binding Name}"/>
                <Run Name="RunChan" Text=" - "/>
                <Run Text="{Binding Occupation}"/>
            </TextBlock>
        </DataTemplate>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Emp1">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ContentControl Content="{Binding Emp1}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Emp2">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ContentControl Content="{Binding Emp2}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <!-- ... -->
    </DataGrid.Columns>
</DataGrid>

Here i use one implicit DataTemplate in the resources but you could also apply it explicitly as the ContentTemplate of each ContentControl by defining & referencing a key but you know that anyway.


Barebone subclassing approach:

public class DataGridTemplateMemberColumn : DataGridTemplateColumn
{
    public static readonly DependencyProperty MemberPathProperty =
            DependencyProperty.Register("MemberPath", typeof(string), typeof(DataGridTemplateMemberColumn), new UIPropertyMetadata(null));
    public string MemberPath
    {
        get { return (string)GetValue(MemberPathProperty); }
        set { SetValue(MemberPathProperty, value); }
    }

    protected override System.Windows.FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        return GenerateContent(CellEditingTemplate, dataItem);
    }

    protected override System.Windows.FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        return GenerateContent(CellTemplate, dataItem);
    }

    private FrameworkElement GenerateContent(DataTemplate template, object dataItem)
    {
        var contentControl = new ContentControl();
        contentControl.ContentTemplate = template;
        if (MemberPath != null)
        {
            Binding binding = new Binding(MemberPath);
            binding.Source = dataItem;
            contentControl.SetBinding(ContentControl.ContentProperty, binding);
        }
        else
        {
            contentControl.Content = dataItem;
        }
        return contentControl;
    }
}

<DataGrid.Columns>
    <cex:DataGridTemplateMemberColumn MemberPath="Emp1" />
    <cex:DataGridTemplateMemberColumn MemberPath="Emp2" />
    <cex:DataGridTemplateMemberColumn MemberPath="Emp3" />
    <cex:DataGridTemplateMemberColumn MemberPath="Emp4" />
    <cex:DataGridTemplateMemberColumn MemberPath="Emp5" />
</DataGrid.Columns>

这篇关于在内置的WPF DataGrid中,我可以为DataGridTemplateColumn设置数据源吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆