2010-05-06 8 views
6

j'ai une colonne définie comme ceci:WPF format texte affiché?

<DataGridTextColumn Binding="{Binding Path=FileSizeBytes, Mode=OneWay}" Header="Size" IsReadOnly="True" /> 

Mais au lieu d'afficher la taille du fichier comme un grand nombre, je voudrais afficher les unités, mais ont toujours la sorte par FileSizeBytes réelle. Y a-t-il un moyen de le faire passer par une fonction ou quelque chose avant de l'afficher?


@Igor:

Fonctionne très bien.

http://img200.imageshack.us/img200/4717/imageget.jpg

[ValueConversion(typeof(long), typeof(string))] 
class FileSizeConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     string[] units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; 
     double size = (long)value; 
     int unit = 0; 

     while (size >= 1024) 
     { 
      size /= 1024; 
      ++unit; 
     } 

     return String.Format("{0:0.#} {1}", size, units[unit]); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Répondre

2

La liaison à une fonction est possible dans WPF, mais il est généralement douloureux. Dans ce cas, une approche plus élégante serait de créer une autre propriété qui renvoie une chaîne formatée et se lier à cela.

class FileInfo { 
    public int FileSizeBytes {get;set;} 
    public int FileSizeFormatted { 
    get{ 
    //Using general number format, will put commas between thousands in most locales. 
    return FileSizeBytes.ToString("G"); 
    } 
    } 
} 

En XAML, se lient à FileSizeFormatted:

<DataGridTextColumn Binding="{Binding Path=FileSizeBytes, Mode=OneWay}" Header="Size" IsReadOnly="True" /> 

EDIT de solution de remplacement, grâce à Charlie pour cette précision.

Vous pouvez écrire votre propre convertisseur de valeur en implémentant IValueConverter.

[ValueConversion(typeof(int), typeof(string))] 
public class IntConverter : IValueConverter { 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 
     //needs more sanity checks to make sure the value is really int 
     //and that targetType is string 
     return ((int)value).ToString("G"); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 
     //not implemented for now 
     throw new NotImplementedException(); 
    } 
} 

Puis en XAML:

<UserControl.Resources> 
    <src:DateConverter x:Key="intConverter"/> 
</UserControl.Resources> 
... 
<DataGridTextColumn Binding="{Binding Path=FileSizeBytes, Mode=OneWay, Converter={StaticResource intConverter}}" Header="Size" IsReadOnly="True" /> 
+1

Dans le cas où vous ne pouvez pas ajouter une autre propriété à la classe source (il peut y avoir plusieurs raisons à cela), l'autre solution serait de créer un IValueConverter et de le donner à la liaison en utilisant la propriété Converter. Ensuite, chaque fois que la liaison sera mise à jour, elle passera d'abord par le code du convertisseur. – Charlie

+0

Oui, bon point. Une alternative à cela consisterait à envelopper la classe source dans un modèle viewmodel, ce qui dans certains cas pourrait être une surcharge. –

+0

La raison pour laquelle je ne veux pas aller avec plus de propriétés est parce que je dois déclencher un événement PropertyChanged pour chacun d'entre eux ... Je pourrais finir avec des dizaines de déclenchements tous pour ce qui est essentiellement la même chose! De plus, vous liez la présentation avec des données. J'aime bien le 2ème sol'n. – mpen

1

Pour des fins de mise, la mise en œuvre appropriée définit un IValueConverter. Vérifiez cet exemple: link text

4

Vous pouvez essayer d'utiliser StringFormat dans votre expression de liaison si vous utilisez .NET 3.5SP1 ou version ultérieure. Voir this post on Lester's WPF Blog ou this post at Vince Sibal's blog pour quelques exemples de syntaxe. L'ajout de StringFormat aux liaisons éliminera la plupart des besoins des Convertisseurs de valeur et conservera commodément votre formatage avec votre balisage plutôt que de le quitter dans une autre classe quelque part. C'est certainement beaucoup moins typé.

Peut-être quelque chose comme ceci fonctionne:

<DataGridTextColumn 
    Binding="{Binding Path=FileSizeBytes, Mode=OneWay, StringFormat='\{0:N0\} bytes'}" 
    Header="Size" IsReadOnly="True" /> 

Je ne sais pas si en cliquant sur l'en-tête pour trier les éléments les classera comme des chaînes ou le type de données sous-jacentes, cependant, si en fonction de ce que votre expression de formatage ressemble, vous pouvez ou ne pouvez pas obtenir le comportement de tri souhaité.