Bind list to listboxitem in wpf - c#

I'm trying to bind a list to a listbox in WPF. But it doesn't seem to work, I just see nothing on screen.
Here is my code:
WPF
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="453" VerticalAlignment="Top" Width="119" Margin="0,43,0,0" ItemsSource="{Binding orderlist}">
<ListBoxItem Content="{Binding orderlist.ID}"></ListBoxItem>
</ListBox>
C#
Order order = new Order();
Klantgegevens klantgegevens = new Klantgegevens();
XmlReader rdr = XmlReader.Create(#"C:\Users\Gebruiker\Desktop\EDI\Rekening.xml");
rdr.ReadToFollowing("datum");
order.DatumOntvangst = rdr.ReadElementContentAsString();
rdr.ReadToFollowing("volgnr");
order.Status = "Aangenomen";
order.Opmerkingen = "";
rdr.ReadToFollowing("naam");
order.Afzender = rdr.ReadElementContentAsString();
rdr.ReadToFollowing("naam");
klantgegevens.Naam = rdr.ReadElementContentAsString();
rdr.ReadToFollowing("straat");
klantgegevens.Straat = rdr.ReadElementContentAsString();
rdr.ReadToFollowing("huisnr");
klantgegevens.Huisnummer = rdr.ReadElementContentAsInt();
rdr.ReadToFollowing("plaats");
klantgegevens.Woonplaats = rdr.ReadElementContentAsString();
rdr.ReadToFollowing("postcode");
klantgegevens.Postcode = rdr.ReadElementContentAsString();
rdr.ReadToFollowing("telefoonnr");
klantgegevens.Telefoonnummer = rdr.ReadElementContentAsString();
order.Klantgegevens = klantgegevens;
orderlist.Add(order);
listBox.DataContext = orderlist;
As you probably know, Order is a custom class, and so is Klantgegevens.
I'm pretty new to binding and WPF in general so excuse me for my stupidness :)

You need to set or bind the ItemsSource property of ListView to an IEnumerable. Since you have set the DataContext property to your "orderlist" you should bind the ItemsSource property directly to the DataContext (ItemsSource="{Binding}"). You should also use an ItemTemplate as suggested by Fruchtzwerg :
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="453" VerticalAlignment="Top" Width="119" Margin="0,43,0,0" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ID}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Also note that the DataContext of the ItemTemplate is an item in your ItemsSource, i.e. an Order object in this case. So to bind to the "ID" property of the Order object you use the binding syntax above. "ID" must be a public property of the Order class.

With
<ListBoxItem Content="{Binding orderlist.ID}"></ListBoxItem>
you are adding an item in XAML. But your plan is to create a template to present bound items. The simplest solution is to use
<ListBox x:Name="listBox" DisplayMemberPath="ID"/>
if only one property needs to be presented. Multiple properties can be showed by creating a template like
<ListView x:Name="listBox">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ID}" />
<TextBlock Text="{Binding datum}"/>
<!-- ... -->
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Furthermore you should use a property like
public ObservableCollection<Klantgegevens> Items { get; } =
new ObservableCollection<Klantgegevens>();
to bind on. Set the DataContext of the whole Window with the ListView to the object, with this property. After that you can bind the ListView with
<ListView ItemsSource="{Binding Items}"/>

Related

Binding listview group header

So, I attempting to, very simply, display items in a Windows 10 listview, and then seperate them by group. Everything is working fine, except that I can't seem to bind the title of the group.
Here is my current xaml:
<ListView ItemsSource="{Binding Source={StaticResource cvsEpisodes}}"/>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding EpisodeNB}"/>
<TextBlock Text="{Binding EpisodeTT}"/>
<TextBlock Text="{Binding EpisodeDESC}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding SEASONNB}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
<Page.Ressources>
<CollectionViewSource x:Name="cvsEpisodes" IsSourceGrouped="True"/>
</Page.Ressources>
And the C#, that is executed by the OnNavigatedTo event:
List < EPISODELST > Episodes = new List < EPISODELST > ();
var episodes = root.episodes.Select(m = >new EPISODELST {EpisodeTT = m.title, EpisodeNB = m.episode.ToString(), EpisodeDESC = m.overview, SEASONNB = m.season.ToString()}).ToList();
foreach(EPISODELST s in episodes)
{
Episodes.Add(new EPISODELST {EpisodeTT = s.EpisodeTT, EpisodeDESC = s.EpisodeDESC, EpisodeNB = "EPISODE " + s.EpisodeNB, SEASONNB = s.SEASONNB });
}
var result = from EPISODELST in Episodes group EPISODELST by EPISODELST.SEASONNB into grp orderby grp.Key select grp;
cvsEpisodes.Source = result;
(EPISODELST and episodes are two classes, but it isn't necessary to paste them here)
I have seen various other implementations of grouped listviews online, but they are all way more complex than this, and I'm guessing that this should work, because I can tell the code can succesfuly sort all the data correctly.
The problem probably just has to do with the TextBlock's binding, but I have tried various other things I found online, such as {Binding=Name}, or {Binding Key.Name}, but nothing seems to work.
So, In the end, this was really simple. I found the awnser burried deep down Microsoft's UWP Github sample page.
It has to be binded to {Binding Key}
Inside GroupStyle:
<TextBlock Text="{Binding Key}"/>

DataTemplate for ListBox element is not binding at all

I have a ListBox element,
which purpose is to show the users the activities,
that are registered on the Database
so that they can choose from them to modify or delete them.
After consulting two very useful answers about using DataContext and DataTemplates,
I decided to implement that knowledge in my project,
unfortunately, it's not working.
When I run it and I select the text on the ListBox,
I only see: DataTemplate templ = new DataTemplate(typeof(Activities));
as its content, and I didn't mark it up as code,
because I want to stress the fact that it appears as a string,
if you will.
I get that there could be more than one workaround for what I'm trying to achieve.
however I really want to understand this, as it appears to be very useful.
Here's the code:
//This is the connection instance to the database
Connection c = new Connection();
DataTemplate templ = new DataTemplate(
typeof(Activities)
);
//The ListActivities method returns
//an ObservableCollection<Activities> list
libTest.DataContext = c.ListActivities(
objSem.getId()
);
libTest.SetBinding(
ItemsControl.ItemsSourceProperty, new Binding()
);
FrameworkElementFactory sp = new FrameworkElementFactory(
typeof(StackPanel)
);
sp.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
sp.Name = "myTemplate";
FrameworkElementFactory date = new FrameworkElementFactory(
typeof(Label)
);
date.SetBinding(Label.ContentProperty, new Binding("date"));
sp.AppendChild(date);
FrameworkElementFactory nameAct = new FrameworkElementFactory(
typeof(Label)
);
nameAct.SetBinding(Label.ContentProperty, new Binding("nameAct"));
sp.AppendChild(nameAct);
FrameworkElementFactory descr = new FrameworkElementFactory(
typeof(Label)
);
descr.SetBinding(Label.ContentProperty, new Binding("descr"));
sp.AppendChild(descr);
FrameworkElementFactory quantity = new FrameworkElementFactory(typeof(Label));
quantity.SetBinding(Label.ContentProperty, new Binding("quantity"));
sp.AppendChild(quantity);
templ.VisualTree = sp;
libTest.ItemTemplate = templ;
i dont like code definition for such thing so here is the xaml one
<DataTemplate DataType="{x:Type local:Activities}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding date}"/>
<Label Content="{Binding nameAct}"/>
<Label Content="{Binding descr}"/>
<Label Content="{Binding quantity}"/>
</StackPanel>
</DataTemplate>
just put this into your resources and all Activities will render like this
pls read something more about binding in WPF, maybe MVVM stuff too. so you would better understand what you need when you do binding with WPF.
a little example
create a class which will be your DataContext and put a public property for your List in it.
public class SampleViewModel
{
public ObservableCollection<Activities> MyActivities {get;set;}
}
xaml.cs: set the DataContext for your View to your Viewmodel class
public partial class SampleWindow : Window
{
private SampleViewModel _data;
public SampleWindow()
{
_data = new SampleViewModel();
InitializeComponent();
this.DataContext = _data;
}
}
xaml: define your Bindings for your controls
<ListBox ItemsSource="{Binding MyActivities}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding date}"/>
<Label Content="{Binding nameAct}"/>
<Label Content="{Binding descr}"/>
<Label Content="{Binding quantity}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
or
<ListBox ItemsSource="{Binding MyActivities}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:Activities}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding date}"/>
<Label Content="{Binding nameAct}"/>
<Label Content="{Binding descr}"/>
<Label Content="{Binding quantity}"/>
</StackPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>

WPF Get CheckBoxes inside ListBox in code

I have this List box and I want to search for its items which were selected (IsChecked=true) by user
<CheckBox Style="{StaticResource ResourceKey=CheckBoxes}"
Name="chkBoxSelectAllStaff" Content="Select All">
</CheckBox>
<ListBox Name="lstStaffs" MaxHeight="250" MinHeight="50" Margin="0,5,5,5" Width="350"
ScrollViewer.VerticalScrollBarVisibility="Auto" HorizontalAlignment="Right"
HorizontalContentAlignment="Right">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Style="{StaticResource ResourceKey=CheckBoxes}" IsChecked="{Binding ElementName=chkBoxSelectAllStaff, Mode=OneWay, Path=IsChecked}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" Margin="0,0,3,0"></TextBlock>
<TextBlock Text="{Binding LastName}" Margin="0,0,3,0"></TextBlock>
<TextBlock Text="{Binding CellphoneNumber}" Margin="0,0,3,0"></TextBlock>
</StackPanel>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
I want to do something like this
foreach(var item in lstStaff.Items){
if((CheckBox) item).IsChecked){
//do something
}
}
And also I am binding the data this way :
//staff is my entity object containing Id, FirstName, LastName, CellphoneNumber
lstStaffs.ItemsSource = args.Result; // comes from webservice call and is Staff[]
lstStaffs.UpdateLayout();
But I get Staff object in lstStaffs.Items!!, So how can I iterate over selected(IsChecked=true) items(staffs) ...
Tnx
From the How to: Find DataTemplate-Generated Elements page at MSDN:
// Getting the currently selected ListBoxItem
// Note that the ListBox must have
// IsSynchronizedWithCurrentItem set to True for this to work
ListBoxItem myListBoxItem = (ListBoxItem)(myListBox.ItemContainerGenerator.
ContainerFromItem(myListBox.Items.CurrentItem));
// Getting the ContentPresenter of myListBoxItem
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);
// Finding textBlock from the DataTemplate that is set on that ContentPresenter
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
TextBlock myTextBlock = (TextBlock)myDataTemplate.FindName("textBlock",
myContentPresenter);
// Do something to the DataTemplate-generated TextBlock
MessageBox.Show("The text of the TextBlock of the selected list item: "
+ myTextBlock.Text);
This shows you how to get access to elements defined in a DataTemplate. However, if you just want to get access to the items from the collection that have been selected, there is a much simpler way:
var selectedItems = lstStaffs.SelectedItems;
You must set the SelectionMode to Multiple or Extended for this to work.

binding the xml to same code page

I am trying to bind a XML page to same underlying code page.
<toolkit:ToggleSwitch Foreground="Transparent" Checked="ToggleSwitch_Checked" IsChecked="{Binding Source={StaticResource appSettings}, Path=LockSetting, Mode=TwoWay}">
<toolkit:ToggleSwitch.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" DataContext="{Binding}">
<TextBlock Text="locks or unlocks your calender" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="statusBox" Text="{Binding stat1}" Style="{StaticResource PhoneTextTitle3Style}" />
</StackPanel>
</DataTemplate>
</toolkit:ToggleSwitch.ContentTemplate>
I have set the data context as
stat1 = "abn";
InitializeComponent();
aps = this.Resources["appSettings"] as AppSettings;
this.colorpicker.Color = Color.FromArgb(aps.ASetting, aps.RSetting, aps.GSetting, aps.BSetting);
ContentPanel.DataContext = this;
But this is not working at all. Any help will be good.
When you write ContentPanel.DataContext = this it implies in this case that the Code-behind of the XAML would be providing context for the data binding. More specifically, when you write {Binding sta1} in the XAML, sta1 must be a property in the code behind. That is, sta1 should be something like that:
public String sta1 { get; set; }

Binding ComboBox ItemsSource in DataGrid RowDetailsTemplate

I am trying to bind an ItemsSource to a ComboBox in a RowDetailsTemplate. If I place a ComboBox outside the grid it works fine. I think this is occureing because of the ItemsSource property on the grid may be throwing off the ComboBox within the RowDetailsTemplate. XAML is below any thoughts?
Categories and CatTypes are two different ObservableCollections.
No error is occurring; the ComboBox just appears empty.
<ComboBox ItemsSource="{Binding CatTypes}"></ComboBox>
<my:DataGrid Name="gridProds" AutoGenerateColumns="False"
AlternatingRowBackground="Gainsboro" ItemsSource="{Binding Categories}">
<my:DataGrid.Columns>
<my:DataGridTextColumn x:Name="CatId" Header="CatID" Width="Auto" Binding="{Binding CategoryID}" />
<my:DataGridTextColumn Header="CatName" Width="Auto" Binding="{Binding CategoryName}" />
</my:DataGrid.Columns>
<my:DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label>ID:</Label>
<TextBox Name="txtGridCatId" Text="{Binding CategoryID}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Category Type:</Label>
<ComboBox ItemsSource="{Binding CatTypes}"></ComboBox>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</my:DataGrid.RowDetailsTemplate>
</my:DataGrid>
There is a class in the called DataSource in which the following is done:
private ObservableCollection<string> _cattypes = new ObservableCollection<string> { };
public ObservableCollection<string> CatTypes
{
get
{
_cattypes = new ObservableCollection<string> { };
SqlConnection con = new SqlConnection("MyConnStringHere;");
SqlCommand cmd = new SqlCommand("Select ID, CatType from PfCategoryType ORDER BY CatType", con);
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string CatType = (string)rdr["CatType"];
_cattypes.Add(CatType);
}
con.Close();
return _cattypes;
}
}
In the MainWindow.xaml.cs I have:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataSource dataSource = new DataSource();
this.DataContext = dataSource;
}
}
If you checked the debug output in VS you would see the actual binding error. Most likely below code will fix it for you.
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=CatTypes}" />
If you can't get RelativeSource to work then use names. The property CatTypes is a property of some class which you created an object for and set as datacontext to some control. Just give that control a name (for example myControl) and bind like this:
<ComboBox ItemsSource="{Binding ElementName=myControl, Path=CatTypes}" />
If that don't work you need to post more of your code to figure out what you are doing wrong.
What happens if you try this?
<ComboBox DataContext="{Binding DataContext, ElementName=myControl}" ItemsSource="{Binding CatTypes}" />
(Of course you'd rename "myControl" to match the name of your window.)
Here, we're setting the data context of the combo box to be the same as the data context of the window. Since this is also the same data context of the first combo box in your XAML, I imagine the second combo box will start behaving like the first. (Although I worry that this will result in some unnecessary database connections, one per grid row.)
On second thought, if you need to set other properties in the context of the row, you won't want to set the data context of the entire ComboBox. In that case, I'd try something like this.
<ComboBox ItemsSource="{Binding ElementName=myControl, Path=DataContext.CatTypes}" SelectedItem="{Binding CategoryType}" />

Categories

Resources