将ContentStringFormat传递到Datatemplate

时间:2018-08-30 15:50:41

标签: c# wpf string-formatting datatemplate

我的目标是将格式化的字符串传递到datatemplate中:

<ContentControl ContentTemplate="{StaticResource WorkingLabelTemplate}"    Content="123"
                ContentStringFormat="Number is {0}" Grid.Row="0"/>

<ContentControl ContentTemplate="{StaticResource NotWorkingLabelTemplate}" Content="123"
                ContentStringFormat="Number is {0}" Grid.Row="1"/>

第一种方法:

<DataTemplate x:Key="WorkingLabelTemplate">
    <Label Content="{Binding}"
            ContentStringFormat="{Binding RelativeSource={RelativeSource TemplatedParent}, 
            Path=ContentStringFormat, Converter={StaticResource TestConverter}}"/>
</DataTemplate>

第二种方法:

<DataTemplate x:Key="NotWorkingLabelTemplate">
    <Label Content="{Binding}" 
            ContentStringFormat="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentControl},
            Path=ContentStringFormat, Converter={StaticResource TestConverter}}"/>
</DataTemplate>

对于这两种方法,TestConverter均表示绑定正常工作:

  

TestConverter:“编号为{0}”,类型为“ System.String”到“ System.String”,参数“   TestConverter:类型'System.String'到'System.String'的'数字为{0}',参数”

但是第二种方法不起作用: screenshot

问题: 为什么第二种方法不起作用,而绑定结果却相同?

1 个答案:

答案 0 :(得分:2)

TL; DR

我使用了您的项目,发现在我的计算机上安装的所有.Net框架中都发生了同样的事情。因此,我挖了更多的北斗星以了解发生了什么,我得出的结论是,这只是一个定时问题,您的工作模板的ContentStringFormat属性正在评估中(而不是绘制标签之前)。

解决方案

要解决您的问题,请从以下位置更改构造函数代码:

public MainWindow()
{
    this.DataContext = this;
    InitializeComponent();
}

收件人:

public MainWindow()
{
    InitializeComponent();
    this.DataContext = this;
}

如果您想阅读一些真正有趣的东西,请继续阅读!

为什么我认为这是时间问题?

我在两个模板diag:PresentationTraceSources.TraceLevel=High上都设置了诊断属性,并在日志后找到了

工作模板 enter image description here

无法使用模板 enter image description here

如果仔细观察这两张图片,您会发现评估ContentStringFormat属性所花费的时间之间存在时间差异。

另一种证明

我对您的项目进行了另一项更改,这证明了我的信念是正确的。如果您在下面运行代码,则该代码类似于您的项目,但有两个附加按钮;一个更改数据,另一个更改字符串格式。当您运行程序并更改字符串格式时,内容不会以新的字符串格式重新呈现,但是当您自行更改数据时,它会重新评估字符串格式并重新呈现控件!

MainWindow.xaml

<Window x:Class="StringFormatTestProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:StringFormatTestProject"
        mc:Ignorable="d"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:TestConverter x:Key="TestConverter"/>

        <DataTemplate x:Key="WorkingLabelTemplate">
            <Label Content="{Binding diag:PresentationTraceSources.TraceLevel=High}"
                   ContentStringFormat="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                 Path=ContentStringFormat, Converter={StaticResource TestConverter}, diag:PresentationTraceSources.TraceLevel=High}"/>
        </DataTemplate>

        <DataTemplate x:Key="NotWorkingLabelTemplate">
            <Label Content="{Binding}"
                   ContentStringFormat="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContentControl},
                                                 Path=ContentStringFormat, Converter={StaticResource TestConverter}}">
            </Label>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>


        <ContentControl ContentTemplate="{StaticResource NotWorkingLabelTemplate}" Content="{Binding SomeDatatInVM}"
                        ContentStringFormat="{Binding FormatStringInVM}" Grid.Row="0"/>

        <ContentControl ContentTemplate="{StaticResource WorkingLabelTemplate}"    Content="{Binding SomeDatatInVM}"
                        ContentStringFormat="{Binding FormatStringInVM}" Grid.Row="1"/>

        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition Width="*" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Button Click="Button_Click" Grid.Column="0">Change Data</Button>
            <Button Click="Button_Click_1" Grid.Column="2">Change Format String</Button>
        </Grid>
    </Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string formatStringInVM = "Peer: {0}";
    public string FormatStringInVM
    {
        get { return formatStringInVM; }
        set
        {
            formatStringInVM = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FormatStringInVM)));
        }
    }

    private int someDatatInVM = 123;
    public int SomeDatatInVM
    {
        get { return someDatatInVM; }
        set
        {
            someDatatInVM = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SomeDatatInVM)));
        }
    }

    public MainWindow()
    {    
        this.DataContext = this;

        InitializeComponent();
    }

    private void Button_Click(Object sender, RoutedEventArgs e)
    {
        SomeDatatInVM++;
    }

    private static int i = 1;
    private void Button_Click_1(Object sender, RoutedEventArgs e)
    {
        FormatStringInVM = "Peer-" + i.ToString() + ": {0}";
        i++;
    }
}