强制更新WPF中的RelativeSource绑定

时间:2013-08-28 22:17:58

标签: wpf binding datatemplate observablecollection itemscontrol

对于我的应用程序,我有一个ItemsControl,它具有第一个项目的不同模板(简称为Template2),以及其余项目的默认模板(Template1)。我使用以下XAML完成了这项工作:

<DataTemplate x:Key="MyDataTemplate">
    <ContentPresenter x:Name="TemplateContentPresenter"
                      Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
                      ContentTemplate="{StaticResource Template1}"/>
    <DataTemplate.Triggers> 
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, 
     Converter= {StaticResource IsFirstItemInCollectionConverter}}"
                     Value="True">
            <Setter TargetName="TemplateContentPresenter"
                    Property="ContentTemplate"
                    Value="{StaticResource Template2}"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

IsFirstItemInCollectionConverter的代码如下:

public class IsFirstItemInCollectionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DependencyObject item = (DependencyObject)value;
        ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
        Console.WriteLine("converted");
        return (ic.ItemContainerGenerator.IndexFromContainer(item) == 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

问题是当我在itemsControl的itemssource中进行更改时,我的绑定不会更新。 (在显示itemsControl的视图中,我有可以添加和删除项目的按钮)。只有在切换视图并重新加载视图后,绑定才会更新并显示正确的模板。我该如何纠正这种行为?我假设我必须将UpdateSourceTrigger设置为显式并手动更新源,但我不知道如何在datatemplate中执行此操作。在此先感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您已在Binding="{Binding RelativeSource={RelativeSource Self}上触发了DataTrigger,当ListBoxItem的datacontext发生更改时,它将被触发。

我建议在这里使用DataTemplateSelector作为项目控件,并为其设置ItemTemplateSelector属性。在SelectTemplate方法中,您可以根据任何逻辑返回新添加项目的模板:

TemplateSelector:

 public class MyTemplateSelector : DataTemplateSelector
{
    public DataTemplate FirstItemTemplate { get; set; }
    public DataTemplate DefaultItemTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        //Logic to return first or default template comes here
    }
}

在xaml:

<local:MyTemplateSelector x:Key="myTemplate">
        <local:MyTemplateSelector.FirstItemTemplate>
            <!--First Template-->
        </local:MyTemplateSelector.FirstItemTemplate>

        <local:MyTemplateSelector.DefaultItemTemplate>
            <!--Default Template-->
        </local:MyTemplateSelector.DefaultItemTemplate>
    </local:MyTemplateSelector>

<强>更新

对于您的特定情况,如果您未在itemsControl中使用交替,您也可以像下面一样解决此问题。您可以将AlternationCount用于ListBox并绑定到每个ListboxItem的ItemsControl.AlternationIndex。因此,每当列表框交替索引发生更改时,您都可以更改其模板:

XAML:

<ListBox AlternationCount="{Binding Items.Count, RelativeSource={RelativeSource Self}}" x:Name="itemControl" ItemsSource="{Binding Items}">
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template" Value="{StaticResource DefaultTemplate}" />
                <Style.Triggers>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                        <Setter Property="Template" Value="{StaticResource FirstTemplate}" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>

这里的DefaultTemplate和FirstTemplate是controlTemplates。

我尝试了它,每当我删除索引0处的项目时,它都适用于我,它为下一个项目提供了第一个项目模板。

希望它适合你。

谢谢,

答案 1 :(得分:0)

好的,我修好了但是态度不雅。我暂时将绑定项设置为null,以便每次删除/添加项时强制DataTemplateSelector重新评估。