0

I try to bind mycollection into wpf:

    private ObservableCollection<MyClass> _coll;

    public ObservableCollection<MyClass> Coll
    {
        get
        {
            if (_coll == null)
                _coll = new ObservableCollection<MyClass>();                
            return _coll;
        }

        set
        {       
            _coll = value;
        }           
    }

MyClass:

 class MyClass 
  {
     int Id;
     String Name1;
     String Name2;
  }

And at WPF:

 <ListBox Grid.Row="1" x:Name="lbKey" BorderBrush="Gray"
                                     ItemsSource="{Binding  Path=Coll}"
                                     ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                                     HorizontalContentAlignment="Stretch"
                                     ItemContainerStyle="{StaticResource ResourceKey=lbStyle}">
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <Border BorderThickness="1" BorderBrush="LightGray" Background="WhiteSmoke"
                                                HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                                            <TextBlock Text="{Binding}" TextWrapping="Wrap" Margin="2"
                                                       Background="Transparent"
                                                       HorizontalAlignment="Stretch"/>
                                        </Border>
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                            </ListBox>

But, when i run program see something like Id.ToString(); So, i have to override ToString() method ,but i can not change MyClass methods.

And i create extension method:

namespace Some.Name.Space
{
   public static class MyClassExtensions
     {
       public static string ToString(this MyClass my)
        {
          return String.Format("{0} {1}"my.Name1,my.Name2);
        }
      }
}

But this is not help to me: i see at my grid strings like this: 1,2 and so on.

Can you tell me, how to override ToString methods at extended method and bind it into WPF.

sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
Admiral Land
  • 2,304
  • 7
  • 43
  • 81
  • 1
    Also note that your MyClass fields are private, your extension method won't even compile, because the fields are private, you can not access them so you can not override the ToString() to return a formatted string like you say you want unless you resort to reflection. – Janne Matikainen Jan 25 '16 at 14:00

3 Answers3

3

Extension method don't override ToString() method because details here: How to create extension method for toString?

BUT..

You don't have to override ToString() method. You are binding but you do not point which property may by bind.

Change this:

<TextBlock Text="{Binding}" TextWrapping="Wrap" Margin="2"
                                                       Background="Transparent"
                                                       HorizontalAlignment="Stretch"/>

To this

<TextBlock Text="{Binding Name1}" TextWrapping="Wrap" Margin="2"
                                                       Background="Transparent"
                                                       HorizontalAlignment="Stretch"/>

Then You can bind exactly value of Name1 property.

and You must also change MyClass (you have to have public property nor fields)

      public class MyClass 
      {
          int Id;
          private string _Name1;
          private string _Name2;

          public string Name1
          {
           get { return _Name1; }
           set { _Name1 = value; }
          }

          public string Name2
          {
           get { return _Name2; }
           set { _Name2 = value; }
          }
       }

BUT...

If You want bind like this Text="{Binding} and You want Your own implementation of display MyClass - You have to override ToString method in MyClass like this:

      class MyClass 
      {
         int Id;
         String Name1;
         String Name2;

         public override string ToString()
         {
           return String.Format("{0} {1}", this.Name1, this.Name2);
         }
     }

It is good patern to do this.

BUT if You can not change MyClass - You can create Your own type and pack MyClass with in

          public class NewMyClass 
          {
             public MyClass myclass {get;set;}

             public override string ToString()
             {
               return String.Format("{0} {1}", mycalss.name1, mycalss.name2);
             }
         }

and change

public ObservableCollection<NewMyClass> Coll

in this solution Your xaml is correct

BUT

If MyClass have private fields like You show where is no way to get that fields to dispaly.

Community
  • 1
  • 1
blogprogramisty.net
  • 1,714
  • 1
  • 18
  • 22
1

I think the better option for this scenario is to create property that gives you a combined name. You can define that property as like this:

 public string DisplayName
  {
     get { return _Name1 + _Name2; }
  }

So that the binding code will be similar to this:

<TextBlock Text="{Binding DisplayName}" TextWrapping="Wrap" Margin="2" ../>

Or the whole class definition will be like the following:

    class MyClass
    {
        public int Id { get; set; }
        private string _Name1;
        private string _Name2;

        public string Name2
        {
            get { return _Name2; }
            set { _Name2 = value; }
        }
        public string Name1
        {
            get { return _Name1; }
            set { _Name1 = value; }
        }
        public string DisplayName
        {
            get { return _Name1 + _Name2; }
        }
    }

This is not the answer to the exact question but This will solve the issue in a pretty good manner.

sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
0

First create a ValueConverter that will take the MyClass instance as a parameter and dig the private fields from the type and then get the values of those fields to return the correct string.

public class MyClassToStringValueConverter : IValueConverter
{
    private static FieldInfo Name1Field;
    private static FieldInfo Name2Field;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (Name1Field == null)
        {
            Name1Field = typeof(MyClass).GetField("Name1", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        if (Name2Field == null)
        {
            Name2Field = typeof(MyClass).GetField("Name2", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        return string.Format("{0} {1}", Name1Field.GetValue(value), Name2Field.GetValue(value));
    }

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

In your xaml, create a resource of this ValueConverter and use it in the binding, below is an example that binds to MyClassProperty of type MyClass in the viewmodel.

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

<TextBox Text="{Binding MyClassProperty, Converter={StaticResource MyClassToStringValueConverter}}"/>
Janne Matikainen
  • 5,061
  • 15
  • 21