Я не верю, что в FlowDocument есть какой-то способ сделать LineBreak
не сломанным, кроме как вытащить его. Вы можете переключиться на использование макета WPF или использовать присоединенное свойство для переключения между LineBreak и пустым Run.
Использование макета WPF
Вы можете вместо этого использовать макет WPF. Примерно так:
<DataTemplate x:Key="Layout1">
<DockPanel>
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="#FF2A4D9E" />
<TextBlock Text="{Binding Price}" FontWeight="Bold" />
<TextBlock Text="{Binding Quantity}" Foreground="#99000000" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="Layout2">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="#FF2A4D9E" />
<TextBlock Text="{Binding Price}" FontWeight="Bold" />
</DockPanel>
<TextBlock Text="{Binding Quantity}" Foreground="#99000000" />
</DockPanel>
</DataTemplate>
Теперь вы можете легко переключаться между макетами, просто переключая DataTemplates.
Автоматическое удаление LineBreaks с помощью привязок
Если вы хотите «скрыть» LineBreak с помощью привязки, вы можете сделать это с помощью присоединенного свойства «BecomeLineBreak», которое при применении к пустому Run и установке в значение true удаляет его и заменяет на LineBreak.
Как магия, теперь у вас есть возможность написать:
<Run my:LineBreakSwitcher.BecomeLineBreak="{Binding SomeCondition}" />
И ваш Run превратится в LineBreak каждый раз, когда свойство SomeCondition имеет значение true.
Вот код:
public class LineBreakSwitcher : DependencyObject
{
public static bool GetBecomeLineBreak(DependencyObject obj) { return (bool)obj.GetValue(BecomeLineBreakProperty); }
public static void SetBecomeLineBreak(DependencyObject obj, bool value) { obj.SetValue(BecomeLineBreakProperty, value); }
public static readonly DependencyProperty BecomeLineBreakProperty = DependencyProperty.RegisterAttached("BecomeLineBreak", typeof(bool), typeof(LineBreakSwitcher), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var oldElement = (Inline)obj;
var newElement = (bool)e.NewValue ? (Inline)new LineBreak() : new Run();
newElement.SetBinding(BecomeLineBreakProperty, oldElement.GetBindingExpression(BecomeLineBreakProperty).ParentBindingBase);
var parent = (Paragraph)oldElement.Parent;
parent.Inlines.InsertBefore(oldElement, newElement);
parent.Inlines.Remove(oldElement);
}
});
Как это работает: когда BecomeLineBreak становится истинным при запуске, создается новый LineBreak, копируется привязка BecomeLineBreak, LineBreak вставляется перед запуском, затем запуск удаляется. Когда BecomeLineBreak становится ложным, создается новый прогон, и весь процесс происходит в обратном порядке.