views:

595

answers:

3

I'm trying to bind some data to a WPF listview. One of the properties of my data type is of type byte[] and I'd like it to be shown as a comma-delimited string, so for example { 12, 54 } would be shown as 12, 54 rather than as Byte[] Array. I think I want to make a custom DataTemplate but I'm not sure. Is that the best way? If so, how do I do it? If not, what is the best way?

EDIT: I only want to use this for one column - the other properties are displayed fine as they are.

+2  A: 

I would create a ValueConverter that creates the comma-delimited string. Then you can bind directly to the byte[], but specify the converter in the binding.

(No need for me to put code when Mark's answer is good.)

Joel B Fant
+5  A: 

I would suggest using a ValueConverter:

[ValueConversion(typeof(byte []), typeof(string))]
public class ByteArrayConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        byte [] bytes = (byte [])value;
        StringBuilder sb = new StringBuilder(100);
        for (int x = 0; x<bytes.Length; x++)
        {
            sb.Append(bytes[x].ToString()).Append(" ");
        }
        return sb.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}

In your xaml, you'd add it to your binding like this:

<Window.Resources>
    <local:ByteArrayConverter x:Key="byteArrayConverter"/>
</Window.Resources>

...

"{Binding ByteArrayProperty, Converter={StaticResource byteArrayConverter}}"
Mark Synowiec
How about: `return BitConverter.ToString((byte[])value).Replace("-", ", ");` as the body of your `Convert` method?
LukeH
Ah beat me to it. Nice answer. :)
Charlie
@Luke: Thats a good idea. I've never used BitConverter, but it looks like it's handy :)
Mark Synowiec
I get "'local' is an undeclared namespace. Line 32, position 10.' XML is not valid."
Simon
@Simon: you'll need to add the namespace reference to local at the top of your xaml file. For instance, if the namespace that you have your ValueConverter defined in is called MyNamespace, you need:<Window x:Class="MyNamespace.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MyNamespace"...
Mark Synowiec
+1  A: 

I set up the following example, which demonstrates the binding using a value converter.

Here is the Window1.xaml.cs:

private ObservableCollection<ByteData> _collection = new ObservableCollection<ByteData>();

public Window1()
{
 InitializeComponent();

 _collection.Add(new ByteData(new byte[] { 12, 54 }));
 _collection.Add(new ByteData(new byte[] { 1, 2, 3, 4, 5 }));
 _collection.Add(new ByteData(new byte[] { 15 }));
}

public ObservableCollection<ByteData> ObservableCollection
{
 get { return _collection; }
}

public class ByteData
{
 byte[] _data;

 public ByteData(byte[] data)
 {
  _data = data;
 }

 public byte[] Data
 {
  get { return _data; }
  set { _data = value; }
 }
}

Here is the Window1.xaml:

<Window x:Class="TestWpfApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApplication"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="Window1" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
 <local:ByteToStringConverter x:Key="byteToStringConverter"/>
</Window.Resources>
<StackPanel>
 <ListView ItemsSource="{Binding ObservableCollection}">
  <ListView.ItemTemplate>
   <DataTemplate>
    <TextBox Width="200" Text="{Binding Path=Data, Mode=TwoWay, 
     UpdateSourceTrigger=PropertyChanged, Converter={StaticResource byteToStringConverter}}"/>
   </DataTemplate>
  </ListView.ItemTemplate>
 </ListView>
</StackPanel>

And here is the value converter:

public class ByteToStringConverter : IValueConverter
{
 public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
 {
  byte[] data = (byte[])value;
  StringBuilder byteString = new StringBuilder();

  int idx;
  for (idx = 0; idx < data.Length - 1; idx++)
  {
   byteString.AppendFormat("{0}, ", data[idx]);
  }
  byteString.Append(data[idx]);

  return byteString.ToString();
 }

 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
 {
  // If you want your byte-data to be editable in the textboxes, 
  // this will need to be implemented.
  return null;
 }
}
Charlie