Как избавиться от пробелов между Runs in TextBlock?
У меня есть XAML:
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="10" FontFamily="Arial" Foreground="#414141">
<Run Text="{Binding LoadsCount}" />
<Run Text="+" />
<Run Text="{Binding BrokerLoadsCount}" />
</TextBlock>
И я получаю отображение следующим образом: 12 + 11
Каким-то образом он вставляет дополнительное пространство между каждым Run
Как мне отобразить 12+11
?
Ответы
Ответ 1
Пробелы между тегами запуска вызывают пробелы, это самое простое исправление.
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="10"
FontFamily="Arial"
Foreground="#414141">
<Run Text="{Binding LoadsCount}" /><Run Text="+" /><Run Text="{Binding BrokerLoadsCount}" />
</TextBlock>
Поскольку все, что находится между <TextBlock>
и </TextBlock>
, нацелено на свойство text TextBlock, пробелы из разрывов между прогонами приводят к эффекту, который вы видите. Вы также можете сократить его до этого.
<Run Text="{Binding LoadsCount}" />+<Run Text="{Binding BrokerLoadsCount}" />
В этой статье MSDN приведены все сведения о том, как xaml обрабатывает пробелы
http://msdn.microsoft.com/en-us/library/ms788746.aspx
Если вам было любопытно, почему перерыв и тонна вкладок переводятся в одно пространство
Все пробельные символы (пробел, строка, вкладка) преобразуются в пространства.
Все последовательные пробелы удаляются и заменяются одним пробелом
Ответ 2
Одна из проблем с хорошим решением Kevin заключается в том, что однострочное форматирование тегов XAML
отменяется, когда вы применяете некоторые функции автоматического переформатирования XAML/XML, например. "ctrl-K + ctrl-D". Обходным решением, которое я нашел, является форматирование тегов Run
следующим образом:
<TextBlock>
<Run FontStyle="Italic"
Text="aaa" /><Run
Text="bbb" />
</TextBlock>
Хотя разделение тега на строки, подобные этому, несколько неудобно, этот формат не будет изменен путем автоматического переформатирования, если вы выберете опцию Visual Studio
"Сохраните новые строки и пробелы между атрибутами" для текстового редактора XAML:
![extra space eliminated between consecutive Run elements in XAML]()
Ответ 3
Другой вариант - прокомментировать пробел между тегами запуска, сохранением прочитанного кода и удалением лишнего места.
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="10" FontFamily="Arial" Foreground="#414141">
<Run Text="{Binding LoadsCount}" /><!--
--><Run Text="+" /><!--
--><Run Text="{Binding BrokerLoadsCount}" />
</TextBlock>
Ответ 4
Я написал Attached Property, чтобы "обходить" это поведение.
public class TextBlockExtension
{
public static bool GetRemoveEmptyRuns(DependencyObject obj)
{
return (bool)obj.GetValue(RemoveEmptyRunsProperty);
}
public static void SetRemoveEmptyRuns(DependencyObject obj, bool value)
{
obj.SetValue(RemoveEmptyRunsProperty, value);
if (value)
{
var tb = obj as TextBlock;
if (tb != null)
{
tb.Loaded += Tb_Loaded;
}
else
{
throw new NotSupportedException();
}
}
}
public static readonly DependencyProperty RemoveEmptyRunsProperty =
DependencyProperty.RegisterAttached("RemoveEmptyRuns", typeof(bool),
typeof(TextBlock), new PropertyMetadata(false));
public static bool GetPreserveSpace(DependencyObject obj)
{
return (bool)obj.GetValue(PreserveSpaceProperty);
}
public static void SetPreserveSpace(DependencyObject obj, bool value)
{
obj.SetValue(PreserveSpaceProperty, value);
}
public static readonly DependencyProperty PreserveSpaceProperty =
DependencyProperty.RegisterAttached("PreserveSpace", typeof(bool),
typeof(Run), new PropertyMetadata(false));
private static void Tb_Loaded(object sender, RoutedEventArgs e)
{
var tb = sender as TextBlock;
tb.Loaded -= Tb_Loaded;
var spaces = tb.Inlines.Where(a => a is Run
&& string.IsNullOrWhiteSpace(((Run)a).Text)
&& !GetPreserveSpace(a)).ToList();
spaces.ForEach(s => tb.Inlines.Remove(s));
}
}
Весь исходный код и объяснение всего этого можно найти здесь.
Используя это прикрепленное свойство, вы можете сохранить форматирование XAML так, как вы хотите, но вы не получите эти пробелы в визуализированном XAML.
Ответ 5
Мое решение состоит в том, чтобы сделать размер шрифта по умолчанию почти невидимым (FontSize="1"
), а затем установить размер шрифта на требуемый размер в каждом из <Run
:
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="1"
FontFamily="Arial"
Foreground="#414141">
<Run FontSize="10" Text="{Binding LoadsCount}" />
<Run FontSize="10" Text="+" />
<Run FontSize="10" Text="{Binding BrokerLoadsCount}" />
</TextBlock>
Возможно, вам лучше сделать это в Code Behind. Я пробовал предыдущие решения, но в некоторых ситуациях VS просто отформатировал тщательно отпечатанный код.
Ответ 6
Я поместил приложение Pieter в WPF (я думаю, это для UWP).
Пример:
<StackPanel>
<TextBlock Text="Before:" FontWeight="SemiBold"/>
<TextBlock>
Foo
<Run Text="Bar"/>
<Run>Baz</Run>
</TextBlock>
<TextBlock Text="After:" FontWeight="SemiBold" Margin="0,10,0,0"/>
<TextBlock local:TextBlockHelper.TrimRuns="True">
Foo
<Run Text="Bar"/>
<Run>Baz</Run>
</TextBlock>
<TextBlock Text="Use two spaces if you want one:" FontWeight="SemiBold" Margin="0,10,0,0"/>
<TextBlock local:TextBlockHelper.TrimRuns="True">
Foo
<Run Text=" Bar"/>
<Run>Baz</Run>
</TextBlock>
</StackPanel>
![screenshot]()
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
public class TextBlockHelper
{
public static bool GetTrimRuns(TextBlock textBlock) => (bool)textBlock.GetValue(TrimRunsProperty);
public static void SetTrimRuns(TextBlock textBlock, bool value) => textBlock.SetValue(TrimRunsProperty, value);
public static readonly DependencyProperty TrimRunsProperty =
DependencyProperty.RegisterAttached("TrimRuns", typeof(bool), typeof(TextBlockHelper),
new PropertyMetadata(false, OnTrimRunsChanged));
private static void OnTrimRunsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBlock = d as TextBlock;
textBlock.Loaded += OnTextBlockLoaded;
}
static void OnTextBlockLoaded(object sender, EventArgs args)
{
var textBlock = sender as TextBlock;
textBlock.Loaded -= OnTextBlockLoaded;
var runs = textBlock.Inlines.OfType<Run>().ToList();
foreach (var run in runs)
run.Text = TrimOne(run.Text);
}
private static string TrimOne(string text)
{
if (text.FirstOrDefault() == ' ')
text = text.Substring(1);
if (text.LastOrDefault() == ' ')
text = text.Substring(0, text.Length - 1);
return text;
}
}