J'ai XAML suivant:
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="10" FontFamily="Arial" Foreground="#414141">
<Run Text="{Binding LoadsCount}" />
<Run Text="+" />
<Run Text="{Binding BrokerLoadsCount}" />
</TextBlock>
Et je reçois un affichage comme celui-ci: 12 + 11
D'une manière ou d'une autre, il insère un espace supplémentaire entre chaque Run
Comment le faire afficher 12+11
?
Les espaces entre les balises d’exécution créent les espaces, c’est le correctif le plus simple.
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="10"
FontFamily="Arial"
Foreground="#414141">
<Run Text="{Binding LoadsCount}" /><Run Text="+" /><Run Text="{Binding BrokerLoadsCount}" />
</TextBlock>
Parce que tout ce qui se situe entre <TextBlock>
et </TextBlock>
cible la propriété text du TextBlock, les espaces entre les pauses entre les exécutions sont à l'origine de l'effet visible. Vous pouvez également le raccourcir à ceci.
<Run Text="{Binding LoadsCount}" />+<Run Text="{Binding BrokerLoadsCount}" />
Cet article MSDN donne toutes les informations sur la manière dont xaml gère les espaces.
http://msdn.Microsoft.com/en-us/library/ms788746.aspx
Si vous étiez curieux de savoir pourquoi une pause et une tonne d’onglets se traduisent par un seul espace
Tous les caractères d'espacement (espace, saut de ligne, tabulation) sont convertis en les espaces.
Tous les espaces consécutifs sont supprimés et remplacés par un espace
Une autre option consiste à commenter l'espace entre les balises Run, en maintenant le code lisible et en supprimant l'espace supplémentaire.
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="10" FontFamily="Arial" Foreground="#414141">
<Run Text="{Binding LoadsCount}" /><!--
--><Run Text="+" /><!--
--><Run Text="{Binding BrokerLoadsCount}" />
</TextBlock>
Un problème avec la solution Nice de Kevin est que le formatage à une seule ligne des balises XAML
est annulé lorsque vous appliquez certaines des fonctions de reformatage automatique XAML/XML, par exemple. "Ctrl-K + Ctrl-D". Une solution de contournement que j'ai trouvée consiste à formater les balises Run
comme suit:
<TextBlock>
<Run FontStyle="Italic"
Text="aaa" /><Run
Text="bbb" />
</TextBlock>
Bien que diviser la balise en plusieurs lignes comme celle-ci soit quelque peu fastidieux, ce format ne sera pas modifié par le reformatage automatique, à condition que vous sélectionniez l'option Visual Studio
"Conserver les nouvelles lignes et les espaces entre attributs" dans l'éditeur de texte XAML:
Ma solution consiste à rendre la taille de police par défaut presque invisible (FontSize="1"
), puis à définir la taille de police à la taille souhaitée à chaque <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>
Vous feriez mieux de le faire dans Code Behind. J'ai essayé les solutions précédentes, mais dans certaines situations, VS a simplement formaté le code soigneusement mis en retrait.
J'ai écrit une propriété attachée pour "contourner" ce comportement.
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));
}
}
Le code source complet et l'explication de tout cela peuvent être trouvés ici . En utilisant cette propriété attachée, vous pouvez conserver votre mise en forme XAML exactement comme vous le souhaitez, mais vous n'obtenez pas ces espaces dans le XAML affiché.
J'ai porté la propriété attachée de Pieter à WPF (je pense que c'est pour UWP).
Exemple:
<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>
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;
}
}