Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Databinding with a listbox

I have a bit of code that reads a json response from an HTTP server, it then parses this and inserts the data into a ListBox control.

The event I fire off when the download is complete is the following:

 void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
 {
     DataContractJsonSerializer ser = null;

     try
     {
         ser =
        new DataContractJsonSerializer(typeof(ObservableCollection<UserLeaderboards>));

         ObservableCollection<UserLeaderboards> users =
            ser.ReadObject(e.Result) as ObservableCollection<UserLeaderboards>;

         foreach (UserLeaderboards em in users)
         {
             int Fid = em.id;
             string Fusername = em.username;
             int Fscore = em.score;
             lstbLeaders.Items.Add(Fid + Fusername + Fscore);
         }
     }
     catch (Exception ex)
     {
         MessageBox.Show(ex.Message);
     }
 }

Now, when I do the items.add I presume it's just joining up the 3 variables and adding it to one column in the ListBox. This works fine and I see all 3 items joined up and displayed.

I want to separate this and make it look a bit nicer so I've created some XAML to try and bind the variables to textblocks. The following is just binding the username. I also have a public class that get/sets all 3 variables.

<ListBox Height="346" HorizontalAlignment="Left" Margin="5,221,0,0" 
         Name="lstbLeaders" VerticalAlignment="Top" Width="446">
   <DataTemplate>                            
       <TextBlock Text="{Binding Source=Fusername}" />                           
   </DataTemplate>
</ListBox>

When running the above I get nothing displayed at all. I have a feeling it's something simple?

Thanks.

like image 549
Nathan Avatar asked May 31 '11 17:05

Nathan


2 Answers

To display a simple string your xaml should look like this:

<ListBox Height="346" HorizontalAlignment="Left" Margin="5,221,0,0" 
         Name="lstbLeaders" VerticalAlignment="Top" Width="446">
    <ListBox.ItemTemplate>
        <DataTemplate>                            
           <TextBlock Text="{Binding}" />                           
        </DataTemplate>
    <ListBox.ItemTemplate>
</ListBox>

and you have to provide an object instead of a simple string if you want to split the properties to make it look nicer. If you just add Fid + Fusername + Fscore you will end up with a plain string.

<ListBox Height="346" HorizontalAlignment="Left" Margin="5,221,0,0" 
         Name="lstbLeaders" VerticalAlignment="Top" Width="446">
    <ListBox.ItemTemplate>
        <DataTemplate>                            
           <StackPanel Orientation="Horizontal">
               <TextBlock Text="{Binding Id}" />                           
               <TextBlock Text="{Binding Name}" />                           
               <TextBlock Text="{Binding Score}" />                           
           </StackPanel> 
        </DataTemplate>
    <ListBox.ItemTemplate>
</ListBox>

You will need a view class:

public class UserView
{
    public string Id {get;set;}
    public string Name {get;set;}
    public int Score {get;set;}
}

in your code behind:

var usersList = new List<UserView>();

foreach (UserLeaderboards em in users)
{
    int Fid = em.id;
    string Fusername = em.username;
    int Fscore = em.score;
    usersList.Add(new UserView { Id = Fid, Name = Fusername, Score = Fscore} );
}

lstbLeaders.ItemsSource = usersList;

Further notes:

  • Why not bind the ObservableCollection<UserLeaderboards> direcectly to the list box?

If there is no reason to convert to an other type skip the foreach part of the code and simply set lstbLeaders.ItemsSource = users;.

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    try
    {
         var ser = new DataContractJsonSerializer(
                    typeof(ObservableCollection<UserLeaderboards>));

         var users = ser.ReadObject(e.Result)
                         as ObservableCollection<UserLeaderboards>;

         lstbLeaders.ItemsSource = users;
     }
     catch (Exception ex)
     {
         MessageBox.Show(ex.Message);
     }
}
  • Take look at the MVVM pattern. If you want to work with XAML you should know about this. It simplifies your work and creates cleaner code.

  • If you want to add edit functionality or data can change you may need to implement INotifyPropertyChanged on the View class.

  • You can use type inference which especially helps when working with cumbersome class names. var list = new ObservableCollection<SomeLongTypeName>() saves much typing and screen estate.

  • Hungarian notation makes me cringe ;)

like image 108
Zebi Avatar answered Sep 30 '22 14:09

Zebi


I think you missed the ItemTemplate. Try this

<ListBox Height="346" HorizontalAlignment="Left" Margin="5,221,0,0" Name="lstbLeaders"         VerticalAlignment="Top" Width="446">
    <ListBox.ItemTemplate>
        <DataTemplate>                                  
            <TextBlock Text="{Binding Source=Fusername}" />                      
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox> 
like image 44
kanchirk Avatar answered Sep 30 '22 15:09

kanchirk