How to Data Bind a List of Strings to a Listbox in Wpf/Wp7

How can I data bind a list of strings to a ListBox in WPF/WP7?

If simply put that your ItemsSource is bound like this:

YourListBox.ItemsSource = new List<String> { "One", "Two", "Three" };

Your XAML should look like:

<ListBox Margin="20" Name="YourListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Update:

This is a solution when using a DataContext. Following code is the viewmodel you will be passing to the DataContext of the page and the setting of the DataContext:

public class MyViewModel
{
public List<String> Items
{
get { return new List<String> { "One", "Two", "Three" }; }
}
}

//This can be done in the Loaded event of the page:
DataContext = new MyViewModel();

Your XAML now looks like this:

<ListBox Margin="20" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

The advantage of this approach is that you can put a lot more properties or complex objects in the MyViewModel class and extract them in the XAML. For example to pass a List of Person objects:

public class ViewModel
{
public List<Person> Items
{
get
{
return new List<Person>
{
new Person { Name = "P1", Age = 1 },
new Person { Name = "P2", Age = 2 }
};
}
}
}

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

And the XAML:

<ListBox Margin="20" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=Age}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Hope this helps! :)

Binding ListBox to List (Collection) in XAML

First, setup the binding in your listbox:

<ListBox x:Name="FileList" ItemsSource="{Binding Files}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=.}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

or

<ListBox x:Name="FileList" ItemsSource="{Binding Files}" DisplayMemberPath="."/>

Next, make sure "Files" is a property in your DataContext (or code behind). (You can't bind to fields, only properties...)

Ideally, you'll want to make Files an ObservableCollection<T> instead of a List<T>, as well. This will allow the binding to handle adding or removing elements correctly.

If you do these two things, it should just work correctly.

how to bind data to listbox in wp7

Looking at your code sample:

  1. Please make sure budgetcategorywise() is called before you do the binding
  2. Please change your binding to:

     <TextBlock Name="txtname" Text="{Binding}"></TextBlock>

The reason for this second change is that your code uses a ToString() in the Linq list generation - which means that the class with its category field is flattened in a string represenation.


If you wish to keep the category field in your binding then use a class for your list items like:

   public class MyListItem
{
public string category { get;set; }
public double total { get;set; }
}

public List<MyListItem> jinal;

public void budgetcategorywise()
{

var q = from shoppingItem p in db.Item1
group p by new { p.category_name } into g
select new MyListItem() { category = g.Key, total = g.Sum(p => p.total_amt) };

jinal = q.ToList();
}

ListBox data binding with List of List containing string string int

Any reason you don't want to create a class type for your row? This will make your life a million times easier when working with XAML.

Create a class type for your row and make it implement INotifyPropertyChanged. Once your class implements INotifyPropertyChanged, it is easy to bind to it in your view.

Let's assume you are following the MVVM pattern. This means you will have a View (which you are coding in XAML) and a ViewModel. This view model is going to be a class that implements INotifyPropertyChanged as well. In the constructor of the view, you will set the DataContext property to a new instance of your ViewModel class.

Now for the list part. In the ViewModel, create an ObservableCollection<MyRow>. An ObservableCollection<T> is a collection type that too implements INotifyPropertyChanged. Or in your case, it sounds like you have a list of these items. If this is true, I recommend encapsulating the list with another custom class. It makes the binding more natural with the MVVM pattern. You can double-nest an ObservableCollection but you'll have to make the decision whether or not that is easy to read and understand. For instance, ObservableCollection<ObservableCollection<MyRow>>. In the following example, I assume you create a class (MySet) to hold the rows as opposed to double-nested lists.

Custom Row Class

public class MyRow : INotifyPropertyChanged
{
public event PropertyChanged;

private string _stringValue = string.Empty;
public string StringValue
{
get { return _stringValue; }
set
{
if( _stringValue != value )
{
_stringValue = value;
if( PropertyChanged != null )
{
PropertyChanged( this, new PropertyChangedEventArgs( "StringValue" ) );
}
}
}
}

// continue with the rest of your properties
}

Row Set Class

public class MySet : INotifyPropertyChanged
{
public event PropertyChanged;

private ObservableCollection<MyRow> _rows = null;
public ObservableCollection<MyRow> Rows
{
get { return _rows; }
set
{
if( _rows != value )
{
_rows = value;

if( PropertyChanged != null )
{
PropertyChanged( this, new PropertyChangedEventArgs( "Rows" ) );
}
}
}
}
}

View Model

public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChanged;

private ObservableCollection<MySet> _rowSets = null;
public ObservableCollection<MySet> RowSets
{
get { return _rowSets; }
set
{
if( _rowSets != value )
{
_rowSets = value;
if( this.PropertyChanged != null )
{
this.PropertyChanged( this, new PropertyChangedEventArgs( "RowSets" ) );
}
}
}
}
}

Now in your XAML, you have some options on how you want to display the nested nature of the list. I recommend the ItemsControl container. All you have to do is set the ItemsSource to your ViewModel's property name and then override the DataTemplate. If you do this, then each item will have the data context of the inner list. Repeat with another ItemsControl and then you'll have the item context be equal to each of the inner items (MyRow).

View's XAML

<ItemsControl
ItemsSource="{Binding Path=RowSets}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl
ItemsSource="{Binding Path=Rows}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Path=StringValue, Mode=OneWay}"
Margin="5,0,0,0"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

And don't forget to set the DataContext of the view to the ViewModel.

View's Code Behind

public class View : UserControl
{
public View()
{
InitializeComponents();

this.DataContext = new ViewModel();
}
}

The code above is not tested and only gives you a general idea of where to go with this.

Update

If you aren't wanting to create a class but merely bind to an array, you can do this too. The binding path allows for indexer syntax. You can enter in the XAML Text="{Binding Path=MyArray[0]}".

If you have an array of an array, the XAML could look as follows:

<ItemsControl ItemsSource="{Binding Path=MyOuterArray}">
<ItemsControl.ItemTemplate>
<!-- The data context here is the inner array so the indexer are applied to the inner array -->
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=[0]}" />
<TextBlock Text="{Binding Path=[1]}" />
<TextBlock Text="{Binding Path=[2]}" />
</StackPanel>
</ItemsControl.ItemTemplate>
</ItemsControl>

A couple other options are to use Converters to translate the values in the array into some string format or to provide a property on the row class that is responsible for formatting the members appropriately. Are you just printing the array elements as strings in a sequence? Then just create a custom property on the row class called 'FormattedValue' and have it return the ToString() concatenation of all the relevant properties.

public class MyRow : INotifyPropertyChanged
{
// ...

public string FormattedValue
{
get
{
return string.Join( ", ", this.MyArray );
}
}
}

Bind List of strings to UI as Checkboxes?

You can do that easily by binding an ItemsControl to the list of strings:

<ItemsControl ItemsSource="{Binding Strings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

However that's not very useful, because you have no easy way to access the state of the CheckBox... A better option would be to wrap the string in a class that also exposes a bool property:

public class CheckableItem<T> : INotifyPropertyChanged
{
public CheckableItem(T value)
{
_value = value;
}

private T _value;
public T Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged("Value");
}
}

private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
}
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

You can then expose a list of CheckableItem<string> instead of a list of strings, and change the XAML as follows:

<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Value}" IsChecked="{Binding IsChecked}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

If you need to test if the CheckBox is checked, just test the IsChecked property in the CheckableItem<T> class.

If you need the CheckBox to have 3 states (checked/unchecked/indeterminate), just declare IsChecked as bool? instead of bool.

WPF Databinding with a ComboBox

Altough the use of the ItemSource is perfectly valid. I suggest you work with Data Binding. Here's a nice definition from MSDN:

Data binding is the process that establishes a connection between the application UI and business logic. If the binding has the correct settings and the data provides the proper notifications, then, when the data changes its value, the elements that are bound to the data reflect changes automatically. Data binding can also mean that if an outer representation of the data in an element changes, then the underlying data can be automatically updated to reflect the change. For example, if the user edits the value in a TextBox element, the underlying data value is automatically updated to reflect that change.

I have answered a question where someone also had a problem with binding items to a ListBox. This is not a ComboBox but the principle is the same. Click here to go the question, and here to go straight to the answer.

Basically it comes down to this:

  • Set up your UI
  • Bind your data

In following code, I changed the properties a bit according to the properties used in the tutorial.

XAML:

<ListBox Margin="20" ItemsSource="{Binding Products}"> 
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=ProductId}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

C#

public class Product 
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}

public class ProductViewModel
{
public List<Product> Products
{
get
{
return new List<Product>
{
new Product{ ProductId = 1, Name = "Product_1" },
new Product{ ProductId = 2, Name = "Product_2" }
};
}
}
}

//Following code can be placed in the Loaded event of the page:
DataContext = new ProductViewModel();

Arrays and listbox

You will need a new class here with elements in all your arrays as properties, e.g.:

Code:

Class MyObject
{
public string Name{get;set;}
public string ID{get;set;}
}

MyObject[] MyObjectList = {new MyObject{Name="Terry",ID="122"}, new MyObject{Name="John",ID="234"},new MyObject{Name="Edvard",ID="665"}};

for(int i=0;i<MyObjectList.Lenght, i++)
ListBoxName.Items.Add(MyObjectList[i]);

XAML

<ListBox x:Name="ListBoxName">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Name="TextBlockName" Text="{Binding Path=Name}" />
<TextBlock Name="TextBlockid" Text="{Binding Path=ID}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

This will solve your problem, but do have a look of Data Binding as @Abbas also suggested.

How to bind data to listbox using its ItemTemplate property?

What you have done so far is excellent. But i am thinking that you might have gone wrong in adding the data to the list.Here is my suggestion.

List<SaveMyPet> source=new List<SaveMyPet>();
source.Add(new SaveMyPet(Name="Dumpy", Birthday="21/3/2012", FavFood="Bone:,DocNo="23",VacDate="21/3/2013",FavToy="Bone"));

listbox_mypet.DataContext=this;
listbox_mypet.ItemSource=source;

You can add as many as SaveMyPet items to the list and add it to the source finally. ObservableCollection also works fine. Doubts over this, comment it!



Related Topics



Leave a reply



Submit