binding an List of objects to a Listbox - c#

i have the following XAML code
<ListBox x:Name="TrackedProgramList" Height="145" Width="605" ItemsSource=" {Binding}" >
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=programName}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox>
I'm binding a List to the Listbox's ItemsSource.
The List contains "FileInfo" objects.
FileInfos is an object with some attributes like "programName", "manufacturer" etc.
The problem now is that the list only displays something like:
Namespace.FileInfo
Namespace.FileInfo
Namespace.FileInfo
...
so i think that the path is incorrect.

The Error you are getting is probably:
Items collection must be empty before using ItemsSource.
There is probably no problem with binding.... your bigest problem is invalid xaml.
I am not sure what you are trying to achieve, but I guess you want to have listbox with horizonatal Stackpanel as ItemsPanel.
Then it should be like this:
<ListBox ... >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
And then you probably want to provide an ItemTemplate
<ListBox ... >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="Red" Width="150" Height="100">
<TextBlock Text="{Binding Path=programName}" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT
After you edited your question it seems that you have new problem. Still... your XAML should not be working. If you used one you provided with your question. It's invalid.
If you are getting result like:
Namespace.FileInfo
Namespace.FileInfo
Namespace.FileInfo
Namespace.FileInfo
then your binding in ItemTemplate is not working correctly. Make sure programName is public property.
The properties you use as binding source properties for a binding must be public properties of your class. Explicitly defined interface properties cannot be accessed for binding purposes, nor can protected, private, internal, or virtual properties that have no base implementation.
As I said. My code works fine.
UPDATE
List<FileInfo> should be ListBox's DataContext... it probably is... since you get this result. What you should check is that in FileInfo class is programName as public property.
It should be something like this.
public class FileInfo : ObservableObject
{
private string _programName;
public string programName
{
get{ return this._programName;}
set
{
this._programName = value;
RaisePropertyChanged(() => this.programName);
}
}
}

Related

Binding complex data to an ItemsControl

So basically I have an list of an object that contains another List of objects. Lets say I have an List of the object Class. And Class contains a list of Students. Every student has a property Name as a simple string.
So basically what I want is the following:
The user can select a class using a ComboBox.
<ComboBox ItemsSource="{Binding Path=Classes}" DisplayMemberPath="Name" />
That works.
After selecting an Item from that ComboBox, the user should see a list of every student in that class (remember the property Name in Students)
I have created a simple ItemsControl for that purpose.
<ItemsControl ItemsSource="{Binding Classes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="Name of the Student">
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
My question is: How do I get access to the students name in my label?
Your view model should have a SelectedClass property, which would be updated by binding it to the ComboBox's SelectedItem property:
<ComboBox ItemsSource="{Binding Classes}"
SelectedItem="{Binding SelectedClass}" .../>
You would then bind the ItemsControl to the Students collection of the selected Class like this:
<ItemsControl ItemsSource="{Binding SelectedClass.Students}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note that the view model must implement the INotifyPropertyChanged interface and fire the PropertyChanged event when SelectedClass changes.
In a quick and dirty approach without a SelectedClass view model property, you could also directly access the ComboBox's SelectedItem like this:
<ComboBox x:Name="cbClasses" ItemsSource="{Binding Classes}" ... />
<ItemsControl ItemsSource="{Binding SelectedItem.Students, ElementName=cbClasses}">
...

WPF ItemsControl Button command binding not working

I have an ItemsControl control that has an ObservableCollection as its ItemsSource. It also has a button located inside of its DataTemplate. The button's Command property is bound to a RelayCommand in the ViewModel (I'm using MVVM Light) and the CommandParameter is bound to the corresponding item in the ItemsSource.
The problem is that the command never fires, for some reason. Code-behind works fine, on the other hand. When debugging the mouse click event handler I can see that the sender (of type Button) has a CommandParameter filled with the correct data whereas Command is null.
What did I miss here?
XAML:
<ItemsControl ItemsSource="{Binding Users}"
Margin="{StaticResource ContentMargin}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="{StaticResource ImageButtonMargin}"
Style="{StaticResource ImageButtonStyle}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.UserSelectedCommand}"
CommandParameter="{Binding}">
<!--...-->
ViewModel:
private ObservableCollection<User> _users;
private RelayCommand<User> _userSelectedCommand;
public ObservableCollection<User> Users
{
get { return _users; }
set
{
_users = value;
RaisePropertyChanged();
}
}
public RelayCommand<User> UserSelectedCommand
{
get { return _userSelectedCommand; }
}
protected override sealed void SetCommands() // called in the constructor which is in turned called by SimpleIoc
{
userSelectedCommand = new RelayCommand<User>((user) => UserSeriesSelected(user));
}
private void UserSelected(User selectedUser)
{
}
Use named Element binding as binding source inside your data template to access commands from root data context. You can use root grid or other containers as named element. ItemsControl iteself can be used too.
<ItemsControl x:Name="MyItems" ItemsSource="{Binding Users}"
Margin="{StaticResource ContentMargin}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="{StaticResource ImageButtonMargin}"
Style="{StaticResource ImageButtonStyle}"
Command="{Binding ElementName=MyItems, Path=DataContext.UserSelectedCommand}"
CommandParameter="{Binding}">
<!--...-->
You need to add "FindAncestor" to your relative source binding:
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}
In my opinion you should change your strategy, put the command in the User class and from that class notify the view-model through an event.
This is going to simplify your xaml code and, in my opinion, making your view-model more coherent.

Access current item in a DataTemplate

The following Control is bound to a List of Users:
<ItemsControl x:Name="Users">
<ItemsControl.ItemTemplate>
<DataTemplate>
How can I pass the user to a Converter in this case, not just properties of it?
I assume you're referring to an IValueConverter instance?
Just leave out the Path parameter of your Binding and it will pass in the current DataContext (in your case a User instance).
This sample assumes your IValueConverter is called MyValueConverter:
<ItemsControl x:Name="Users">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Converter={StaticResource MyValueConverter}}" />
</DataTemplate>
<ItemsControl.ItemTemplate>
</ItemsControl>

Bind Dictionary to ItemsControl in C#/WPF

I'm trying to bind KeyValuePair Elements from a Dictionary to a ItemsControl.
My Dictionary has 15 Elements and the following code shows me 15 TextBoxes:
<WrapPanel Name="PersonsWrapPanel" Grid.Row="0">
<ItemsControl ItemsSource="{Binding Persons}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Width="auto">
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Value.Text}"></TextBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
Unfortunately without any TextBox content (which would be Key or Value).
Any ideas?
Perhaps try binding directly to the values of the dictionary:
ItemsSource="{Binding Persons.Values}"
If I am understanding your XAML properly, each object in the dictionary has a field called "Text" to which you are trying to bind. If so and you make the above changes, you will need to change your DataTemplate as well:
<TextBox Text="{Binding Text}" />
See this article for more info. HTH.
I solved it by using this line:
<TextBox Text="{Binding Value, Mode=OneWay}"></TextBox>
The code on http://www.dev102.com/2008/03/07/binding-a-wpf-control-to-a-dictionary/ doesn't seem to work.
Let us say you have a Dictionary called RowValues, with both the [key, value] defined as [string, string].
Now to bind to the Value Pair of this dictionary, you can do the following:
<ItemsControl ItemsSource="{Binding RowValues.Values}" >
To display the text (Value), you can bind as:
<TextBlock Text="{Binding}"/>

Silverlight - Binding with ObservableCollections

This is no doubt a newbish question, but I have looked for an answer to no avail. My setup is simple: I have a ListBox control defined in XAML and an ObservableCollection<MyClass> in the same class. I am binding the ObservableCollection<MyClass> to the ListBox.
Within the hierarchy of this ListBox in XAML, I want to bind to a given MyClass object, not to a child property of the MyClass object.
To clarify, I have XAML that looks like the following (I bind the ObservableCollection in code):
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl MyClassObj="{Binding !!!}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Surely there is a way to get at the object of an ObservableCollection rather than being forced to bind to one of its child properties.
You do not have to specify a Path if you want to use the bound object itself:
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl MyClassObj="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
BTW: Instead of your custom property, you can use the DataContext property of your control to bind the control to the object:
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As well as specifying the binding path in your XAML you have to bind your collection to the ListBox.
C#
ObservableCollection<MyClass> myCollection = new ObservableCollection<MyClass>();
MyListBox.DataContext = myCollection;
The XAML you have used won't be particularly useful unless you have overriden the ToString method on MyClass. Even though you say you're not are you sure it's not a property of MyClass that you want to bind to? I can't see why you'd want to bind directly to a collection object.
XAML
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl MyClassObj="{Binding Path=MyClassProperty}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Categories