Display custom object data to ListBox WPF - c#

I have a ListBox in WPF application as :
<ListBox HorizontalAlignment="Left" Margin="16,37,0,16" Name="lbEmpList" Width="194" SelectionChanged="lbEmpList_SelectionChanged" FontSize="12" SelectionMode="Single">
</ListBox>
I have three buttons: Add, Remove and Update that will add, remove and update items to the list box. I am adding Items to the ListBox my custom class object names objEmployee.
This custom class contains few properties: Id, Name, Address.
But, when I add the object to ListBox, then it will display items as
<Namespace Name>.<Custom Object name>
How can I bind any of the object property to this ListBox at Design or run time to acheive my functionality?

Couple of options:
The first, easiest option is to set the ListBox's DisplayMemberPath property to a property of your custom object. So if your Employee class has a LastName property you could do this:
<ListBox DisplayMemberPath="LastName" ... />
If you want more control over the data that's displayed for each item (including custom layout etc) then you'll want to define a DataTemplate for each item in your ListBox. The easiest way to do this is by simply setting the ListBox's ItemTemplate property:
<ListBox ...>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Have a read through the links I've provided and check out some of the example code on MSDN.

Related

Auto-scroll Listbox based on TextBox text

In WPF and MVVM pattern, I have a TextBox and a ListBox. The ListBox is bound to a collection of items using a DataTemplate. The default count for this collection is about 50 or so.
What I wanted to achieve is a filter-like action. If it's possible, I wouldn't like to change the list view or anything like that, but simply to scroll to the item corresponding to the TextBox match, preferably without selecting it.
I've seen some examples and solutions using CollectionView and Filter (couldn't get it to work btw), and some using auto-scroll to the end of the list or to a new added item, but none specific to my case.
My Listbox is structured as follows:
<ListBox IsTextSearchEnabled="True" HorizontalAlignment="Stretch" Margin="6,49,0,0" Name="lbObjectA" VerticalAlignment="Stretch" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type src:Dto}">
<StackPanel Height="20" Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" Margin="0,3,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

How to bind to a source inside a ListBox different from the ItemsSource already specified

I have a ListBox inside a HubSection, whose Items are bound to a class "players" added to my DefaulViewModel via code behind.
First I simply put a TextBox bound to the property "PlayerName" of my class "players".
Now I would like to add a ComboBox with some items that are NOT part of the class players.
Is it possible ? I thought that definind an ItemsSource in the ComboBox would sort of override the ItemsSource of the ListBox, but nothing displays.
The DataContext of the whole page is defined like so:
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
Then the HubSection is like so:
<HubSection x:Name="HubSec1">
<DataTemplate>
<ListBox x:Name="ListBox1" ItemsSource="{Binding players}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=PlayerName, Mode=TwoWay}"/>
<ComboBox ItemsSource="{Binding Path=ListOfElements}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</HubSection>
If I define the ComboBox in the same way but outside the ListBox, it will display the string elements of "ListOfElements" properly.
But in this ListBox, the ComboBox is empty. So my guess is that having defined an ItemsSource for the ListBox, it is not possible to override it.
I have tried to define a DataTemplate but was not successful doing so, but it might be the good solution (and I did not proceed properly)
What am I missing ?
Edit :
The ComboBox items is an ObservableCollection. It is not part of the "players" class.
Here is how I added these elements to the DefaultViewModel
DefaultViewModel.Add("players", players);
DefaultViewModel.Add("MyItemsList", ListOfElements);
You can walk up the visual tree and bind to an ancestors datacontext:
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
EX:
{Binding Path=ListOfItems, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}
that should give you the datacontext that the listbox has, so assuming your ListOfItems exists in that data context.
Or you can name your control, and then bind to its datacontext by element name:
{Binding ElementName=mySourceElement,Path=ListOfItems}
It can be a little bit tricky to create a good working binding in Windows Apps. A widely used work around is to use the Tag property.
<ListBox x:Name="ListBox1" ItemsSource="{Binding players}" Margin="0,184,0,0" Tag="{Binding Path=ListOfElements}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=PlayerName, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Tag, ElementName=ListBox1}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
A binding to an element wirh the specific name will work always. And the ListOfElements should be in the scope of the ListBox so you can use the Tag property as a proxy. If you need to bind more than one property, you can also use dummy XAML elements:
<Border Tag="{Binding ...}" Name="dummy1"/>

How to add more items to ItemsControl after binding

In my C# windows phone app, I create a binding to bind a list of string to ItemsControl.
// MyCollections is a List<string>
<ItemsControl x:Name="ContentRoot" ItemsSource="{Binding MyCollections}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding }" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It works. But My question is how can I add my own item (e.g. 'Click to add more') to this ItemsControl after it is binded?
There are two answers to this question:
Use an ObservableCollection instead of a List, as it will notify the UI when items are added/removed from it. Then you just add your new item to the list in the view model.
Use a CompositeCollection so you can have the "additional" item without modifying the actual collection.
Normally you would do 1, but since you want a "Click to add more" type of option, CompositeCollection is probably the way to go.
Since you metioned windows phone (but tagged WPF) you may want to look at this post for how to write your own CompositeCollection object: how to do a CompositeCollection in WP8?
Use CompositeCollection to add additional items in your XAML. This should work:
<StackPanel x:Name="stackPanel">
<StackPanel.Resources>
<CompositeCollection x:Key="myCollection">
<CollectionContainer Collection="{Binding DataContext.MyCollections,
Source={x:Reference stackPanel}}"/>
<ContentControl Content="Click to add more"/>
</CompositeCollection>
</StackPanel.Resources>
<ItemsControl x:Name="ContentRoot"
ItemsSource="{StaticResource myCollection}"/>
</StackPanel>

C# WPF Binding to DataBase

Hei all. If something would be not clear then please tell
I have dataGrid and TreeView.
I have loaded data base as Entity Data Model and some tables.
One of these tables "relation" should show to the datagrid. But its (relation table) column depend of the other tables as system,model,function and device. In the Data grid should be 4 columns which contain names of these system,model,function and device. (the picture 1 as should be)
Problem in the how it all show. DataSource don't work well... see picture 2.
<Grid DataContext="{StaticResource relationsViewSource}">
<DataGrid AutoGenerateColumns="True" Name="gridInventory" HorizontalContentAlignment="Right" Margin="255,12,12,128" ItemsSource="{Binding}" />
<StackPanel Height="391" HorizontalAlignment="Left" Margin="10,10,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="239" DataContext="{StaticResource systemsViewSource}" >
<TreeView Height="391" Name="treeView1" Width="239" VerticalContentAlignment="Top" HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding}" />
</StackPanel>
</Grid>
Picture 1:
Picture2:
You are binding both the TreeView and some of your DataGrid columns to an object, but not telling WPF how to draw the object. When WPF doesn't know how to draw an object, it by default draws it using a TextBlock with the Text bound to the object's .ToString()
You need to set the ItemTemplate to tell WPF how to draw your individual objects, such as this:
<TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TreeView.ItemTemplate>
You could also use an implicit DataTemplate to tell WPF how to draw specific objects. This is just a DataTemplate that specifies a DataType without a Key, and WPF will use it anytime it tries to render an object of the specified type.
If you want to avoid removing AutoGenerateColumns="True" and manually specifying your DataGrid's columns, this is probably the method to use.
<DataGrid.Resources>
<DataTemplate DataType="{x:Type local:Device}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</DataGrid.Resources>
The TreeView you would need to set the Path on the Binding to the property you want to display,
The Devices is a collection and you need to put a Listview in there or something that will display a collection and then put a DataTemplate on it to display what you need, either that or bind to a converter to return a static string representation of the Device list
Or just get someone to do it all for you as seems the case on here lol

Display properties of the ListBox.ItemsSource

I am new to WPF. I have a ListBox that has its ItemSource set to a instance of WorkItemCollection. (A collection of WorkItem objects.)
When the list is displayed it only displays the type of each object (Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem). Is there a way to make the list display WorkItem.Title?
You have two options.
The simplest method is to set the DisplayMemberPath property of your ListBox to "Title".
If you want to set not only what gets displayed, but the type of control that is used to display it, then you would set the ListBox's ItemTemplate.
For what your goal is, I would recommend the first option.
You can set a DataTemplate on the ItemTemplate property of the ListBox:
<ListBox ItemSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate DataType="tfs:WorkItem">
<StackPanel>
<TextBlock Text="{Binding Title}" />
<!-- Others -->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Categories