TL; DR
Я использовал ваш проект и обнаружил, что то же самое происходит во всех платформах .Net, установленных на моей машине. Итак, я выкопал еще один ковш, чтобы выяснить, что происходит, и в заключение пришел к выводу, что это просто проблема синхронизации , ContentStringFormat
свойство для вашего рабочего шаблона оценивается немного раньше (до того, как метка была ), чем для вашего неработающего шаблона.
Решение
Чтобы решить вашу проблему, измените код конструктора с:
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
Кому:
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
Продолжайте читать, если хотите прочитать что-то действительно интересное!
Почему я считаю, что это проблема времени?
Я установил свойства диагностики для обоих шаблонов diag:PresentationTraceSources.TraceLevel=High
и обнаружил следующий журнал.
Рабочий шаблон

Не работает шаблон

Если вы внимательно посмотрите на оба изображения, вы увидите, что между временем, затраченным на оценку свойства 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++;
}
}