Data not binding to ListBox WPF - c#

XAML
<Page x:Class="ManufacturingWPF.ShowHardware"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ManufacturingWPF"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="ShowHardware">
<Grid Background="AliceBlue">
<ListBox x:Name="HardwareList" ItemsSource="{Binding Hardware}" HorizontalAlignment="Left" Height="122" Margin="76,36,0,0" VerticalAlignment="Top" Width="149">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Date}"/>
<TextBlock Text="{Binding Nodes}"/>
<TextBlock Text="{Binding Repeaters}"/>
<TextBlock Text="{Binding Hubs}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code Behind C#
public partial class ShowHardware : Page
{
public ShowHardware()
{
InitializeComponent();
DisplayData();
}
public void DisplayData()
{
//Datamodel MDM used for ADO and table creation
//Test is a class used to pass the model and as the name suggest
test it
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> x = t.GetHardware();
foreach(Hardware i in x )
{
HardwareList.ItemsSource = i.Hubs.ToString();
}
}
}
}
I'm facing issues binding the data to the listbox as shown in the XAML and code-behind content.
I've tried previous answers without any luck , did my research but apparently I'm missing out something or maybe there is something I don't quite understand.
Itemsource as the name suggest should bind to the source of where my data is being held. In this case the source would be my class Hardware that holds data for Nodes, date , hubs etc etc.
And in the textblock I manually bind these properties and display the values.
But this is not working.
P.S. My DB table is populated.

That's because the ItemsSource is an IEnumerable and you assign to it the list of hardware itself. So you code should look something like this :
ManufacturingDataModel MDM = new ManufacturingDataModel();
Test t = new Test(MDM);
List<Hardware> x = t.GetHardware();
HardwareList.ItemsSource = x;
//or
foreach (Hardware h in x)
HardwareList.Items.Add(h);

This code seems wrong
foreach(Hardware i in x )
{
HardwareList.ItemsSource = i.Hubs.ToString();
}
Then ItemsSource for Binding has to be a Collection (List, ObservableCollecion, IEnumerable<> ...).
Try HardwareList.ItemsSource = x; and remove the foreach loop
I hope this can help you.

Related

Windows Wpf how can I dynamically create xaml grid using c#

Using Visual Studio 2019 + Resharper.
hey guys, i want to add listviews, that show things from objects, which i get from a list.
it looks like this, when i code it manually:
The XAML-Code:
<ListView Margin="43,313,642,29" BorderThickness="2" BorderBrush="Red" x:Name="Module1">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="Modul"/>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and the c# code:
List<Module> somename = pPP_2.Components.Modules.Values.Cast<Module>().ToList();
List<Module> whatevername = new List<Module>(){somename[0]};
Module1.ItemsSource = whatevername;
The Modules i refer to have several properties, and the {somename[0]} just gets the first of them and puts it in the list.
So basically my question:
How can i create such xaml code using c#? I want to create a listview like this for each element in my list. i DonĀ“t want to create them manually but let the code do it for me.
thinking about this for days now and would love to get some help here.
Thanks,
IRezzet.
P.S. You can basically ignore the special list i created there. The question should work for every List.
You could use an ItemsControl with a ItemTemplate that renders a ListView that has an ItemTemplate rendering the listview-items. If this gets too complex, consider seperating this into a usercontrol to make it more generic.
The XAML would look something like this:
<ItemsControl x:Name="DynamicGrid">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListView BorderThickness="2" ItemsSource="{Binding SubChildren}" BorderBrush="Red">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You will need two Model types for this
// And an instance variable
public ObservableCollection<Outer> Lists { get; } = new ObservableCollection<Outer>();
public class Outer
{
public ObservableCollection<Inner> SubChildren { get; } = new ObservableCollection<Inner>();
}
public class Inner
{
public string Name { get; set; }
}
I used this code to seed for testing:
for (int i = 0; i < 10; i++)
{
var o = new Outer();
for (int k = 0; k < 10; k++)
{
o.SubChildren.Add(new Inner() { Name = "ID: "+k });
}
Lists.Add(o);
}
DynamicGrid.ItemsSource = Lists;

Set Content of an Element without a Name-Property

I'm using a ListBox in combination with a ObservableCollection. The content is set via a TemplateSelector (TextBlock or Label). The text has to be formatted (f.e. with Run-Tags in Code-behind), but i can't access the Items. Is there a solution to get the elements?
I've tried the usage of OfType<>, but this works only on Panels. I searched for an children-attribute but, there isn't one for ListBoxes. Setting the Name-Property via binding is not possible for UId and Name.
An IEnumerator for the LogicalChildren doesn't work and iterate over the whole content everytime a new element is added, is not so optimal. Here a minimal example.
<Window.Resources>
<DataTemplate x:Key="TextBlockTemplate">
<StackPanel>
<TextBlock />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="LabelTemplate">
<StackPanel>
<Label/>
</StackPanel>
</DataTemplate>
<local:myTemplateSelector x:Key="myTemplateSelector" x:Name="myTemplateSelector" TextBlockTemplate="{StaticResource TextBlockTemplate}" LabelTemplate="{StaticResource LabelTemplate}"/>
</Window.Resources>
<Grid Margin="0">
<ListBox Name="mylist" Grid.Row="3"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding _listEntries}"
ItemTemplateSelector="{StaticResource myTemplateSelector}"
>
</ListBox>
</Grid>
Greetings and thanks :)
The TextBlock has an Inlines property that returns the Inline elements that comprise the contents of the TextBlock.
The Label has a Content property that you, depending on how you are using it, may cast to a Panel.
There are no inline elements for a TextBox.
Now, I found a solution. I made the TextBlock and Label as User Control and set the Name-property. In the code-behind, I have access to the DataContext and the element can set itself.
<UserControl x:Class="Test.TextBlockControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TextBlockControl"
Loaded="UserControl_Loaded">
<Grid>
<StackPanel HorizontalAlignment="Stretch" Margin="0,0,0,0">
<TextBlock Name="textBlock"/>
</StackPanel>
</Grid>
In the Code behind i can now access the values and set:
public partial class TextBlockControl : UserControl
{
public List<string> name => DataContext as List<string>;
public TextBlockControl()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (var t in name)
{
var run = new Run(t.Text);
if (t.IsHighlighted)
{
run.Foreground = Brushes.Green;
}
else
{
run.Foreground = Brushes.Red;
}
textBlock.Inlines.Add(run);
}
}
}
}
In the MainWindow, the dataTemplate then references the UserControl (root is the namespace):
<root:PickControl />

How to display individual item names in a WPF ListBox using Data Binding?

In my WPF application, I have a ListBox in my main screen. I'm trying to use the MVVM pattern, so I have a ViewModel associated with the View. When I launch the application, my ViewModel gets initiated, and it reads in a bunch of DLLs I've placed in a directory. Each DLL contains a "Strategy" class, so when I read the DLLs, I retrieve these Strategy class objects and put them in a list (actually an ObservableCollection) which is a member of my ViewModel. I'm using this member list, named DllList, to populate the ListBox.
My ViewModel looks like the following (unnecessary bits removed for clarity):
public class ViewModelPDMain : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ViewModelPDMain() {
dllList = new ObservableCollection<Strategy>();
selectedStrategy = new Strategy();
}
private ObservableCollection<Strategy> dllList = null;
private Strategy selectedStrategy = null;
public ObservableCollection<Strategy> DllList
{
get { return dllList; }
set {
dllList = value;
RaisePropertyChanged("DllList");
}
}
public Strategy SelectedStrategy
{
get { return selectedStrategy; }
set {
selectedStrategy = value;
RaisePropertyChanged("SelectedStrategy");
}
}
}
Then in my main View, I bind it as follows.
<Window x:Class="PrisonersDilemma.Source.View.ViewPDMain"
xmlns:local="clr-namespace:PrisonersDilemma.Source.View"
DataContext="{Binding Source={StaticResource mainViewModelLocator}, Path=ViewModelPDMain}"
Title="Iterated Prisoner's Dilemma" Height="500" Width="800" MinHeight="500" MinWidth="800">
<Grid Name="gridMain">
...
<!-- More stuff here -->
...
<ListBox Name="listStrategies" SelectedIndex="0"
ItemsSource="{Binding DllList}" SelectedItem="{Binding SelectedStrategy}"
Grid.Column="0" Grid.Row="1" Grid.RowSpan="2"
Width="Auto" MinWidth="120"
Margin="3"
BorderBrush="LightGray" BorderThickness="1">
</ListBox>
...
<!-- More stuff here -->
...
</Grid>
</Window>
When I do this and run the application my list box looks like below which is expected.
The problem is when I try to display a property inside my Strategy objects. My Strategy class contains another class, named StratInfo, which in turn contains a string property, StrategyName. My requirement is to display this string value as listbox item values instead of what you can see above.
So I do the following in my View:
<Window x:Class="PrisonersDilemma.Source.View.ViewPDMain"
xmlns:local="clr-namespace:PrisonersDilemma.Source.View"
DataContext="{Binding Source={StaticResource mainViewModelLocator}, Path=ViewModelPDMain}"
Title="Iterated Prisoner's Dilemma" Height="500" Width="800" MinHeight="500" MinWidth="800">
<Grid Name="gridMain">
...
<!-- More Stuff Here -->
...
<ListBox Name="listStrategies" SelectedIndex="0"
ItemsSource="{Binding DllList}" SelectedItem="{Binding SelectedStrategy}"
Grid.Column="0" Grid.Row="1" Grid.RowSpan="2"
Width="Auto" MinWidth="120"
Margin="3"
BorderBrush="LightGray" BorderThickness="1">
<!-- Added Stuff -->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Label Name="lblFirstName"
Content="{Binding SelectedStrategy.StratInfo.StrategyName, Mode=OneWay}"
Grid.Column="0"></Label>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
...
<!-- More Stuff Here -->
...
</Grid>
</Window>
When I do this, I expect the list box items to contain a label, and it to display my StrategyName value. However, I get a listbox which contains 25 items (I have 25 DLLs), but all 25 items are empty.
Funny thing is, I tried to bind the SelectedStrategy.StratInfo.StrategyName to a text box Text property, and it worked. That is, when I click any empty listbox item, it displays the StrategyName in the text box. Please refer to the following figure. You can see that the listbox contains items but the content values aren't displayed. In addition, to the right, the Strategy Name text box is a text box where I have bound the SelectedStrategy.StratInfo.StrategyName and it displays the correct value on item select event.
I have done this exact same thing in a simpler project, and it works just fine. I can't figure out what I'm doing wrong here.
Any thoughts?
Your binding in the data template is incorrect. The data context within the data template is an item in the DllList which is of type Strategy. So your Label should be like so:
<Label Name="lblFirstName"
Content="{Binding StratInfo.StrategyName, Mode=OneWay}"
Grid.Column="0"/>

List box with over 100 items crashes

I am working on windows phone 8 app.
I have List box with over 200 items to display.
<DataTemplate x:Key="DataTemplate1">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="White" Height="400" Width="400" CornerRadius="30,30,30,30">
</Border>
<Grid Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="5,20,5,5"
Foreground="#000000"
Text="{Binding Title}"/>
</Grid>
</Grid>
</DataTemplate>
But it crashes, i have debugged it till 100 items it works but after that it crashes.
In the PhoneApplicationPage_Loaded method i have
private void PhoneApplicationPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
myList.Add(new MyObject("A","A value"));
myList.Add(new MyObject("B", "B value"));
myList.Add(new MyObject("C", "C value"));
and so on... 200 items
ListBoxItems.ItemsSource = myList;
}
how can i fix this ?
Update :
<ItemsPanelTemplate x:Key="ItemsPanelTemplate">
<local:CollectionFlowPanel ItemHeight="400"
ItemWidth="400"
FocusedItemOffset="120"
UnfocusedItemOffset="20"
ItemVisibility="5">
<VirtualizingStackPanel />
</local:CollectionFlowPanel>
</ItemsPanelTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="#000000">
<local:CollectionFlow x:Name="ListBoxItems"
ItemTemplate="{StaticResource DataTemplate}"
ItemsPanel="{StaticResource ItemsPanelTemplate}"/>
</Grid>
Ensure you have VirtualizingStackPanel inside the ItemsPanelTemplate of your list box, see this answer for more info.
Here's the XAML you likely need for your ListBox:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
You need to read following blog from msdn on visualization of the data in list and grid.
Using virtualization with a list or grid
Without seeing your whole xaml code I cannot suggest the exact answer but my guess is that you in xaml ListBox is placed inside a canvas/StackPanel or scrollviewer control.
When the size of the ItemsControl's viewport isn't restricted, the control doesn't perform virtualization. Instead, it creates an item container for each item in its collection. Some common containers that don't restrict the viewport size are Canvas, StackPanel, and ScrollViewer. You can enable virtualization in this situation by setting the size of ItemsControl directly, instead of letting it be sized by its parent container.
Here, we set the Height and Width on the GridView. This restricts the size of the viewport, and items outside of the viewport are virtualized.
Below are 2 scenarios one will throw out of memory exception and other will work fine(use your same code behind and test)
1. ListBox in Canvas
<Canvas .....
<ListBox Name="ListBoxItems".....
</ListBox>
</Canvas>
Above code will throw out of memory exception as items control's viewport is not defined (if you still want to use Canvas than define width/height if ListBox in that case the port of Items control is defined and virtulazation will apply)
2. ListBox in Grid
<Grid .....
<ListBox Name="ListBoxItems".....
</ListBox>
</Grid>
The above code will not throw out of memory exception as virtuallization is applied on the listbox.
Hope this will help
How big is your object ? If your object is too big you might not be able to load them all at once.
Did you try using the for loop?
public List<Fellow> fellowList { get; set; }
private void PhoneApplicationPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
fellowList = new List<Fellow>();
for (int i = 0; i < 2; i++)
{
Fellow fellow = new Fellow();
fellow.x = "B" + i;
fellow.value = "B Value" + i;
fellowList.Add(fellow);
}
this.DataContext = this;
ListBoxItems.ItemsSource = fellowList;
}
public class Fellow
{
public string x { get; set; }
public string value { get; set; }
}
Hope it helps..change the view model according to your wish

ObservableCollection from Linq

Can someone see what I need to change here? I am displaying an observablecollection of AddressTypeClass items. The object items show up in the listbox instead of the data. I can see the data in the objects in debug mode.
THE XAML.CS FILE:
DataContext MyTableDataContext = new MyTableDataContext();
ObservableCollection<AddressTypeClass> theOC = new ObservableCollection<AddressTypeClass>(new MyTableDataContext().AddressTypes.AsEnumerable()
.Select(lt => new AddressTypeClass
{
AddressTypeID = lt.AddressTypeID,
AddressType = lt.AddressType,
})
.ToList());
this.listBox1.ItemsSource = theOC;
THE XAML FILE:
<ListBox Name="listBox1" Margin="8" Height ="200" Width ="150" FontSize="12" Foreground="#FF2F3806" ItemsSource="{Binding AddressType}" IsSynchronizedWithCurrentItem="True" >
</ListBox>
You need to add an ItemTemplate to your ListBox, e.g.
<ListBox Name="listBox1" Margin="8" Height ="200" Width ="150" FontSize="12" Foreground="#FF2F3806" ItemsSource="{Binding AddressType}" IsSynchronizedWithCurrentItem="True" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=AddressType}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can impove your code by using my ObservableComputations library. In your code you manualy update theOC every time MyTableDataContext.AddressTypes dbSet (I assume you are using EntityFramework) changes (new item or remove) or properties (AddressType.AddressTypeID, AddressType.AddressType) changes. Using AddressType you can automate that process:
DataContext MyTableDataContext = new MyTableDataContext();
ObservableCollection<AddressTypeClass> theOC = MyTableDataContext.AddressTypes.Local
.Selecting(lt => new AddressTypeClass
{
AddressTypeID = lt.AddressTypeID,
AddressType = lt.AddressType,
});
this.listBox1.ItemsSource = theOC;
theOC is ObservableCollection and reflects all the changes in the MyTableDataContext.AddressTypes.Local collection and properties mentioned in the code above. Ensure that all properties mentioned in the code above notify of changes through the INotifyProperytChanged interface.

Categories