DataTemplateSelector及其奇怪的行为

时间:2013-03-21 10:02:04

标签: wpf xaml wpf-controls datatemplate

我在DataTemplateSelector内使用ContentControl。根据3种不同的DataTemplates,我有3种不同的object types。当我将content的{​​{1}}设置为所提及类型的数据时,ContentControl会切换到特定的DataTemplateSelector并且选择器更多似乎回滚/重置旧模板。为什么会这样?

编辑:我发现这些值会被重置,因为我有一个附加属性,而且它的OnPropertyChangedCallback在其内部通知我有关在DataTemplates之间交换时值为null的Prop。您可以在下面的代码中看到附加属性。

有人可以帮助我解决DataTemplate的交换机制背后发生的事情吗?

以下是对代码的更深入解释:

DataTemplateSelector

选择器如下所示。它在public void Window1() { InitalizeComponents(); } public void OnClick(object sender, RoutedEventArgs e) { if(this.DataContext == null) this.DataContext = "Hallo"; else{ if(this.DataContext is string) this.DataContext = 123; else{ if(this.DataContext is int) this.DataContext = null; } } } By clicking on Button few times I change the type and so in ContentControl the selector changes to DataTemplate. textDataTemplate之间交换,还有一个模板。正如我所提到的,我有numericDataTemplatestringint这三种类型,我希望不要提及。他们的and one more被称为DataTemplatestextDataTemplate,还有一个。 :)

numericDataTemplate

<local:MyTemplateSelector x:Key="dataTemplateSelector" TextTemplate="{StaticResource textDataTemplate}" NumericTemplate="{StaticResource numericDataTemplate}"/> public class MyTemplateSelector : DataTemplateSelector { public DataTemplate TextTemplate; public DataTemplate NumericTemplate; public DataTemplate Select(object item, Culture.....) { if(item is string) { return this.TextTemplate; } else { return this.NumericTemplate; } } } 和XAML看起来像这样:

ContentControl

这就是<Button Click="OnClick" Content="Click Me"/> <ContentControl Name="contentCtrl" Content="{Binding}" Width="123" ContentTemplateSelector="{StaticResource dataTemplateSelector}" /> 看起来相似的方式。

textDataTemplate

<DataTemplate x:Key="textDataTemplate"> <TextBox x:Name="text" my:AttProperties.Prop="{extension:MarkupExt value}" Text="{Binding Path=Txt, Mode=Default, UpdateSourceTrigger=Explicit}"/> </DataTemplate> 看起来与numericDataTemplate相似,只是只允许数字。

textDataTemplate是来自Prop attached property AttProperties class的{​​{1}}。 type string位于所有三个DataTemplate中。 Prop上方Prop位于TextBox,但也可能是Labelmarkupextension只是“返回Hello”。扩展仅用于测试如何创建自定义markupextension。扩展没什么大不了的。交换DataTemplates时不应该做太多。

再一次解释我的问题。交换似乎是reselts / rollback我的旧模板。我从textDataTemplate交换为numericDataTemplate,而textDataTemplate的Prop则设置为null,但之前的值为“Hello”。

为什么会这样?使用tiggers似乎是相同的行为。一旦Trigger不再有效,它就会回滚使用的值。 DataTemplateSelector是否使用某种与Triggers相同的机制?

被修改: 附加属性只是一个带有OnPropertyChangedCallback的简单.RegisterAttached。在OnPropertyChangedCallback内部,我认为在交换dataTemplates时prop是null。

1 个答案:

答案 0 :(得分:3)

如果在数字模板中使用双向绑定,并且只接受Double之类的内容,则可以将值设置为数字。但没有人能够确定没有看到完整的代码。您自己的代码可能会出错。 要更好地理解事物,请创建自己的控件,从ContentControl派生,并在样本中使用它。然后覆盖控制方法OnContentxxxChanged,在那里插入断点并调试应用程序。您应该了解,您的数据和模板选择器发生了什么。当应用程序在断点处停止时,请仔细检查所有值并查看堆栈跟踪。要调试绑定,您可以插入IValueConverters,它会在代码中放置,您可以在其中检查值。

我真的建议你先做最简单的工作,然后转到更复杂的事情,例如文本框,双向绑定到某些控件的属性,你没有在你的问题中显示。这是一个使用TextBlocks的工作版本:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    public void OnClick(object sender, RoutedEventArgs e)
    {
        if (this.DataContext == null)
            this.DataContext = "Hallo";

        else if (this.DataContext is string)
            this.DataContext = 123;

        else if (this.DataContext is int)
            this.DataContext = null;
    }
}
public class MyTemplateSelector : DataTemplateSelector
{
    public DataTemplate TextTemplate {get; set;}

    public DataTemplate NumericTemplate {get; set;}

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is string)
        {
            return this.TextTemplate;
        }
        else
        {
            return this.NumericTemplate;
        }
    }
}

和xaml:

    <Grid>
    <Grid.Resources>
        <DataTemplate x:Key="numericDataTemplate">
            <TextBlock Foreground="Red" Text="{Binding}" />
        </DataTemplate>
        <DataTemplate x:Key="textDataTemplate">
            <TextBlock Foreground="Green" Text="{Binding}"/>
        </DataTemplate>
        <local:MyTemplateSelector x:Key="dataTemplateSelector"
                             TextTemplate="{StaticResource textDataTemplate}"
                             NumericTemplate="{StaticResource numericDataTemplate}"/>
    </Grid.Resources>
    <StackPanel>
        <Button Click="OnClick" Content="Click Me" VerticalAlignment="Top"/>
        <ContentControl Name="contentCtrl"
                Content="{Binding}" 
                Width="300" Height="100" 
                ContentTemplateSelector="{StaticResource dataTemplateSelector}" />
        </StackPanel>
</Grid>

与您的代码比较。从DataTemplateSelector继承时,应覆盖SelectTemplate方法,不要使用其他名称创建方法。所有控件(如ContentControl)仅使用SelectTemplate。等。

显然,所有的工作和DataTemplateSelector都没有错。我想,你的问题在你的数据和绑定中的某个地方

看看你的OnClick方法 - 它总是将DataContext设置为null