web-dev-qa-db-fra.com

Comment se débarrasser des espaces entre les exécutions dans TextBlock?

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 RunComment le faire afficher 12+11?

49
katit

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

110
Kevin DiTraglia

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>
16
helder.tavares.silva

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:

extra space eliminated between consecutive Run elements in XAML

15
Glenn Slayden

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. 

1
Viktor Jasper

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é.

1
Pieter Nijs

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>

 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;
    }
}
0
Vimes