在DataGridTemplateColumn中使用TemplateSelector时,绑定不再起作用

时间:2018-07-10 15:15:16

标签: c# wpf xaml datatemplate datatemplateselector

我有以下(有效的)XAML定义:

<DataGridTemplateColumn Header="Station &amp; Programm" Width="*">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>                                                
            <ListBox 
                ItemsSource="{Binding Targets}" 
                Style="{StaticResource ListBoxTransparentStyle}"    
                VerticalAlignment="Center"
                IsHitTestVisible="False"> <!--Disable Selection-->
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition SharedSizeGroup="A"/>
                                <ColumnDefinition Width="5"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock
                                Grid.Column="0"
                                Text="{Binding Station}"
                                Height="Auto"/>
                            <TextBlock
                                Grid.Column="2"
                                Text="{Binding Program}"
                                Height="Auto"/>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

我想将此DataTemplate外包,并使用以下DataTemplateSelector

public class ZlsRouteEditorDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate ViewDataTemplate { get;set; }
    public DataTemplate EditDataTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is ERouteEditor e)
        {
            switch (e)
            {
                case ERouteEditor.View:
                    return ViewDataTemplate;
                case ERouteEditor.Edit:
                    return EditDataTemplate;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        return base.SelectTemplate(item, container);
    }
}

然后,我将代码更改如下:

<ControlTemplate>
    <ControlTemplate.Resources>
        <DataTemplate x:Key="StationProgramView" x:Shared="True">                                                
            <ListBox 
                ItemsSource="{Binding Targets}" 
                Style="{StaticResource ListBoxTransparentStyle}"    
                VerticalAlignment="Center"
                IsHitTestVisible="False"> <!--Disable Selection-->
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid >
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition SharedSizeGroup="A"/>
                                <ColumnDefinition Width="5"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <controls:HtTextfeld
                                Grid.Column="0"
                                Text="{Binding Station}"
                                DisableTranslation="True"
                                Height="Auto"/>
                            <controls:HtTextfeld
                                Grid.Column="2"
                                Text="{Binding Program}"
                                DisableTranslation="True"
                                Height="Auto"/>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DataTemplate>
        <DataTemplate x:Key="StationProgramEdit" x:Shared="True">                                                
            <TextBlock Text="Hello World"></TextBlock>
        </DataTemplate>
        <recipeControls:ZlsRouteEditorDataTemplateSelector x:Key="StationProgramTemplateSelector" ViewDataTemplate="{StaticResource StationProgramView}" EditDataTemplate="{StaticResource StationProgramEdit}"/>

<DataGridTemplateColumn Header="Station &amp; Programm" Width="*">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ContentControl
                ContentTemplateSelector="{StaticResource StationProgramTemplateSelector}"
                Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=recipeControls:ZlsRouteEditor}, Path=Mode}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

正确选择了DataTemplate,但是数据绑定不再起作用。

2 个答案:

答案 0 :(得分:1)

尝试设置列的CellTemplateSelector属性,而不是将CellTemplate设置为ContentControl

<DataGridTemplateColumn Header="Station &amp; Programm" Width="*" CellTemplateSelector="{StaticResource StationProgramTemplateSelector}" />

DataContext的{​​{1}}中根元素的ContentTemplate是同一ContentControl的{​​{1}}。

答案 1 :(得分:0)

这是我的个人解决方案,如何使其正常工作。

我已经更改了ZlsRouteEditorDataTemplateSelector类,使其能够查找我的特定控件(ZlsRouteEditor)并获得Mode值。

ZlsRouteEditorDataTemplateSelector

public class ZlsRouteEditorDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate ViewDataTemplate { get;set; }
    public DataTemplate EditDataTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is ERouteEditor e)
            return _GetTemplate(e);

        ZlsRouteEditor parent = container.TryFindParent<ZlsRouteEditor>();
        if (parent != null)
            return _GetTemplate(parent.Mode);

        return base.SelectTemplate(item, container);
    }

    private DataTemplate _GetTemplate(ERouteEditor e)
    {
        switch (e)
        {
            case ERouteEditor.View:
                return ViewDataTemplate;
            case ERouteEditor.Edit:
                return EditDataTemplate;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }
}

TryFindParent

/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the
/// queried item.</param>
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static T TryFindParent<T>(this DependencyObject child) where T : DependencyObject
{
    //get parent item
    DependencyObject parentObject = GetParentObject(child);

    //we've reached the end of the tree
    if (parentObject == null) return null;

    //check if the parent matches the type we're looking for
    T parent = parentObject as T;
    if (parent != null)
    {
        return parent;
    }
    else
    {
        //use recursion to proceed with next level
        return TryFindParent<T>(parentObject);
    }
}

然后直接调用它(如 mm8 所述)

<DataGridTemplateColumn Header="Station &amp; Programm" Width="*" CellTemplateSelector="{StaticResource StationProgramTemplateSelector}"/>

  

在哪里,为什么以及何时需要Mode属性?

我已将recipe对象绑定到ZlsRouteEditor控件以查看编辑 recipe

为避免多个控件或StylesZlsRouteEditorViewZlsRouteEditorEdit ...),我在enum中将ERouteEditor DependencyProperty设为ZlsRouteEditor DataTemplates来更改Template内部特定区域的<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <recipeControls:ZlsRouteEditor Height="570" Margin="5" Mode="View"/> <recipeControls:ZlsRouteEditor Height="570" Margin="5" Mode="Edit"/> </StackPanel>

enter image description here

 <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:local="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">
            <MvxListView
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                android:divider="#000000"
                android:dividerHeight="3px"
                local:MvxBind="ItemsSource Weather; ItemClick ListItemClickCommand"
                local:MvxItemTemplate="ItemTemplateId weatherListItem"
                SelectedItem="{mvx:MvxBind CurrentWeather}"/>
    </LinearLayout>