绑定到XAML中WPF DataGridCell内容的问题 [英] Problems binding to a the content of a WPF DataGridCell in XAML

查看:133
本文介绍了绑定到XAML中WPF DataGridCell内容的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下文章来实现绑定到动态对象列表的数据网格。



将DynamicObject绑定到具有自动列生成的DataGrid



ITypedList方法GetItemProperties工作正常,一个网格显示了我所描述的所有列。



我使用一个自定义PropertyDescriptor,并覆盖GetValue和SetValue方法,如上述帖子所述我也在动态对象中实现了TryGetMember和TrySetMember方法。



所以基本上我有一个ComplexObject:具有字段字典的DynamicCobject和一个实现ITypedList和IList的ComplexObjectCollection。 / p>

这一切都可以正常工作,除非我将DataGrid的itemsSource绑定到集合中,单元格将显示SimpleObject类型名称,我实际上想实现一个模板在文本块中显示SimpleObject的属性值。



我已经使用各种方法来尝试获取底层的SimpleObject,但没有任何作用,我总是得到ComplexObject为行。我使用自动生成的列,这似乎总是产生一个文本列,这可能是问题,但为什么我仍然可以从单元格属性的某个地方获取底层的SimpleObject?



以下是我的理想解决方案,但这不行。

 < Grid> 
< Grid.Resources>
< DataTemplate x:Key =DefaultNodeTempate>
< ContentControl Content ={Binding RelativeSource = {RelativeSource TemplatedParent},
Path = Content}>
< ContentControl.Resources>
< DataTemplate DataType =local:SimpleObjectType>
< TextBlock Text ={Binding Value}/>
< / DataTemplate>
< /ContentControl.Resources>
< / ContentControl>
< / DataTemplate>
< /Grid.Resources>
< DataGrid ItemsSource ={Binding ElementName = mainWin,Path = DynamicObjects}>
< DataGrid.Resources>
< Style TargetType =DataGridCell>
< Setter Property =ContentTemplateValue ={StaticResource DefaultNodeTempate}/>
< / Style>
< /DataGrid.Resources>
< / DataGrid>
< / Grid>

任何建议将不胜感激。



谢谢



Kieran

解决方案

所以我发现解决方案是在代码背后做一些工作。



在AutoGenerationColumn事件中,创建一个带有内容控件和自定义模板选择器的DataTemplate(我在Xaml中创建了一个选择器,并将其发现为一个资源)。



使用e.PropertyName创建一个ContentControl的ContentProperty绑定作为路径



创建一个新的DataGridTemplateColumn,并将新列CellTemplate设置为新的DataTemplate



将e.Column替换为新列,并且将其中的单元格datacontext与动态属性绑定列。



如果任何人有任何改进,请随时分享您的想法。



谢谢

编辑:根据请求我的解决方案的一些示例代码



自定义模板选择器:

  public class CustomDataTemplateSelector:DataTemplateSelector 
{
public列表< DataTemplate>模板{get;组;

public CustomDataTemplateSelector()
:base()
{
this.Templates = new List< DataTemplate>();
}

public override DataTemplate SelectTemplate(object item,DependencyObject container)
{
DataTemplate template = null;
if(item!= null)
{
template = this.Templates.FirstOrDefault(t => t.DataType是Type?(t.DataType as Type)== item.GetType ():t.DataType.ToString()== item.GetType()。ToString());
}

if(template == null)
{
template = base.SelectTemplate(item,container);
}

返回模板;
}
}

XAML:

 < Window x:Class =WpfApplication1.MainWindow
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/演示文稿
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
xmlns:local =clr-namespace:WpfApplication1
Title =MainWindow Height =350Width =525>
< Grid x:Name =ParentControl>
< Grid.Resources>
< local:CustomDataTemplateSelector x:Key =MyTemplateSelector>
< local:CustomDataTemplateSelector.Templates>
< DataTemplate DataType ={x:Type local:MyCellObject}>
< TextBox Text ={Binding MyStringValue}IsReadOnly ={Binding IsReadOnly}/>
< / DataTemplate>
< / local:CustomDataTemplateSelector.Templates>
< / local:CustomDataTemplateSelector>
< /Grid.Resources>
< DataGrid ItemsSource ={Binding Rows}AutoGenerateColumns =TrueAutoGeneratingColumn =DataGrid_AutoGeneratingColumn>
< / DataGrid>
< / Grid>
< / Window>

代码背后:

  private void DataGrid_AutoGeneratingColumn(object sender,DataGridAutoGeneratingColumnEventArgs e)
{
//获取模板选择器
CustomDataTemplateSelector selector = ParentControl.FindResource(MyTemplateSelector)作为CustomDataTemplateSelector;

//创建包装内容控件
FrameworkElementFactory view = new FrameworkElementFactory(typeof(ContentControl));

//设置模板选择器
view.SetValue(ContentControl.ContentTemplateSelectorProperty,selector);

//绑定到属性名
view.SetBinding(ContentControl.ContentProperty,new Binding(e.PropertyName));

//创建数据表
DataTemplate template = new DataTemplate {VisualTree = view};

//创建新列
DataGridTemplateColumn newColumn = new DataGridTemplateColumn {CellTemplate = template};

//设置列和hey presto我们绑定数据
e.Column = newColumn;
}

可能有更好的方法来创建数据模板,我最近看过微软建议使用XamlReader,但这是我当时所做的。另外我还没有在动态类上测试这个,但我确定它应该以任何方式工作。


I used the following post to implement a datagrid bound to a list of dynamic objects

Binding DynamicObject to a DataGrid with automatic column generation?

The ITypedList method GetItemProperties works fine, a grid is displayed with all the columns I described.

I use a custom PropertyDescriptor and override the GetValue and SetValue methods as described in the above post, I also implement the TryGetMember and TrySetMember methods in the dynamic objects.

so basically I have a ComplexObject:DynamicCobject with a field Dictionary and a ComplexObjectCollection implementing ITypedList and IList.

This all works fine except when I bind the itemsSource of the DataGrid to the collection, the cells will show the SimpleObject type name and I actually want to implement a template to show the property Value of the SimpleObject in a text block.

I've used all sorts of methods to try and get the underlying SimpleObject but nothing works and I always get the ComplexObject for the row. I am using autogenerated columns and this always seems to produce a text column, this may be the problem but why cant I still get the underlying SimpleObject from somewhere in the cell properties?

Below would be my ideal solution but this does not work.

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="DefaultNodeTempate">
            <ContentControl Content="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                              Path=Content}">
                <ContentControl.Resources>
                        <DataTemplate DataType="local:SimpleObjectType">
                            <TextBlock Text="{Binding Value}" />
                        </DataTemplate>
                </ContentControl.Resources>
            </ContentControl>
        </DataTemplate>
    </Grid.Resources>
    <DataGrid ItemsSource="{Binding ElementName=mainWin, Path=DynamicObjects}">
        <DataGrid.Resources>
            <Style TargetType="DataGridCell">
                <Setter Property="ContentTemplate" Value="{StaticResource DefaultNodeTempate}" />
            </Style>
        </DataGrid.Resources>
    </DataGrid>
</Grid>

Any suggestions would be much appreciated.

Thanks

Kieran

解决方案

So I found the solution was to do some work in the code behind.

In the AutoGeneratingColumn event create a DataTemplate with a content control and a custom template selector (I create the selector in Xaml and found it as a resource).

Create a binding for the ContentProperty of the ContentControl with e.PropertyName as the path

Create a new DataGridTemplateColumn and set the new columns CellTemplate to your new DataTemplate

replace e.Column with your new column and hey presto the cells datacontext bind with the dynamic property for that column.

If anyone has any refinement to this please feel free to share your thoughts.

Thanks

EDIT: As requested some sample code for my solution

Custom template selector:

public class CustomDataTemplateSelector : DataTemplateSelector
{
    public List<DataTemplate> Templates { get; set; }

    public CustomDataTemplateSelector()
        : base()
    {
        this.Templates = new List<DataTemplate>();
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate template = null;
        if (item != null)
        {
            template = this.Templates.FirstOrDefault(t => t.DataType is Type ? (t.DataType as Type) == item.GetType() : t.DataType.ToString() == item.GetType().ToString());
        }

        if (template == null)
        {
            template = base.SelectTemplate(item, container);
        }

        return template;
    }
}

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="ParentControl">
        <Grid.Resources>
            <local:CustomDataTemplateSelector x:Key="MyTemplateSelector" >
                <local:CustomDataTemplateSelector.Templates>
                    <DataTemplate DataType="{x:Type local:MyCellObject}" >
                        <TextBox Text="{Binding MyStringValue}" IsReadOnly="{Binding IsReadOnly}" />
                    </DataTemplate>
                </local:CustomDataTemplateSelector.Templates>
            </local:CustomDataTemplateSelector>
        </Grid.Resources>
        <DataGrid ItemsSource="{Binding Rows}" AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" >
        </DataGrid>
    </Grid>
</Window>

Code behind:

private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    // Get template selector
    CustomDataTemplateSelector selector = ParentControl.FindResource("MyTemplateSelector") as CustomDataTemplateSelector;

    // Create wrapping content control
    FrameworkElementFactory view = new FrameworkElementFactory(typeof(ContentControl));

    // set template selector
    view.SetValue(ContentControl.ContentTemplateSelectorProperty, selector);

    // bind to the property name
    view.SetBinding(ContentControl.ContentProperty, new Binding(e.PropertyName));

    // create the datatemplate
    DataTemplate template = new DataTemplate { VisualTree = view };

    // create the new column
    DataGridTemplateColumn newColumn = new DataGridTemplateColumn { CellTemplate = template };

    // set the columns and hey presto we have bound data
    e.Column = newColumn;
}

There may be a better way to create the data template, I have read recently that Microsoft suggest using a XamlReader but this is how I did it back then. Also I haven't tested this on a dynamic class but I'm sure it should work either way.

这篇关于绑定到XAML中WPF DataGridCell内容的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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