ListView doesn't see binding object properties - c#

I have a trouble with displaying properties of instance of external class. There is ListView markup:
<ListView
x:Name="transportListView"
SelectionMode="None"
ItemsSource="{Binding MyModel}">
<ListView.ItemTemplate>
<DataTemplate>
<Border Padding="15" HorizontalAlignment="Center" Margin="0,0,0,10" Background="Gray">
<StackPanel Margin="0,0,0,0">
<TextBlock
Text="{Binding ItemName}"
Margin="0,0,0,0"/>
<TextBlock
Text="{Binding ItemCount}"
Margin="0,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
MyModel is the page property:
...
public ObservableCollection<ExternalClass> MyModel { get; set; }
...
ExternalClass is the class in some referenced library:
namespace Library.Entities
{
public class ExternalClass
{
public string ItemName { get; set; }
public int ItemCount { get; set; }
}
}
So when I run my application I see list items because I set grey color, but ItemName and ItemCount is not displaying, why? I adding items to collection correctly and binding works for internal classes perfectly.

Change your ListView's ItemsSource to ItemsSource="{Binding}". Like this:
<ListView x:Name="transportListView" ItemsSource="{Binding}">
....
Also in the code behind add this.DataContext = MyModel; below the InitializeComponent();:
public Window1()
{
InitializeComponent();
this.DataContext = MyModel;
}

To Use ListView you also need to Define View (GridView) for it:
<ListView ItemsSource="{Binding MyModel}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Name" DisplayMemberBinding="{Binding ItemName}"/>
<GridViewColumn Width="140" Header="Count" DisplayMemberBinding="{Binding ItemCount}" />
</GridView>
</ListView.View>
</ListView>
If you want to define template for each row then you can use a ListBox instead of ListView:
<ListBox ItemsSource="{Binding MyModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Padding="15" HorizontalAlignment="Center" Margin="0,0,0,10" Background="Gray">
<StackPanel Margin="0,0,0,0">
<TextBlock Text="{Binding ItemName}" Margin="0,0,0,0"/>
<TextBlock Text="{Binding ItemCount}" Margin="0,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Related

C# ListView Grouping binding error

I failed to perform grouping in list view. It shows error code as:
BindingExpression path error: Indicator' property not found on 'object' ''CollectionViewGroupInternal'`.
may I know which part of my code is wrong?
Below is the class code:
Data are pulled from the database.
foreach(string value in getCountry)
{
string[] values = value.Split(',');
string countryname = values[0].ToString();
string indicator = values[1].ToString();
items.Add(new User() { CountryName = countryname, Indicator = indicator });
}
lvUsers.ItemsSource = items;
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(lvUsers.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Indicator"); //i expect error is from here
view.GroupDescriptions.Add(groupDescription);
public class User
{
public string CountryName { get; set; }
public string Indicator { get; set; }
}
Below is the XAML CODE:
<ListView Name="lvUsers" FontSize="25" FontFamily="Arial">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn DisplayMemberBinding="{Binding CountryName}" />
<GridViewColumn DisplayMemberBinding="{Binding Indicator}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding Indicator}" FontSize="30" FontFamily="Arial" Foreground="Black"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
In the HeaderTemplate, the binding property should be Name rather than Indicator.
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding Name}" FontSize="30" FontFamily="Arial" Foreground="Black"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>

WPF BIndings based on certain condition... to be done entirely using Xaml

Here is my Xaml for the ListView
<ListView x:Name="duplicateVarsInCompXMLListView" ItemsSource="{Binding}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="306">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="ComponentID: " FontWeight="Bold" Foreground="Brown" />
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Variable Name: " Foreground="Green"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Variable Value: " Foreground="Blue"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code-behind
private ObservableCollection<Component> mastercomponentcollection;
mastercomponentcollection = //code to populate the collection
duplicateVarsInCompXMLListView.DataContext = this.mastercomponentcollection;
Classes Involved
public class Component
{
private ObservableCollection<ComponentParameter> parameters = new ObservableCollection<ComponentParameter>();
public string Name
{
get;
set;
}
public ObservableCollection<ComponentParameter> Parameters
{
get{return parameters;}
set{parameters = value;}
}
}
public class ComponentParameter
{
public string Name
{
get;set;
}
public string Value
{
get;set;
}
public bool HasErrors
{
get;
set;
}
public bool IsDuplicate
{
get; set;
}
public bool IsMissing
{
get;set;
}
Here I want to show the bindings only for those collection items where the IsDuplicate is set to true. I believe DataTemplate.Triggers is the way to go but I can't figure out the exact syntax to make it work. Any suggestions?
Here is the ItemContainerStyle for your ItemsControl to hide the items with Duplicate as false.
<ItemsControl ItemsSource="{Binding Parameters}">
<ItemsControl.ItemContainerStyle>
<Style >
<Style.Triggers>
<DataTrigger Binding="{Binding IsDuplicate}" Value="false">
<Setter Property="UIElement.Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
If you want to display two different DataTemplate depending on the IsDuplicate property, you can use DataTemplateSelector.
Create a class derived from DataTemplateSelector that selects the DataTemplate
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate FirstTemplate { get; set; }
public DataTemplate SecondTemplate { get; set; }
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
var model = item as ComponentParameter;
if (model.IsDuplicated)
return FirstTemplate;
return SecondTemplate;
}
}
Create it in your resources and define the templates in your xaml:
<local:MyTemplateSelector x:Key="itemTemplateSelector">
<local:MyTemplateSelector.FirstTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Variable Name: " Foreground="Green"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Variable Value: " Foreground="Blue"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</local:MyTemplateSelector.FirstTemplate>
<local:MyTemplateSelector.SecondTemplate>
<DataTemplate>
<!-- Implementation without bindings goes here -->
</DataTemplate>
</local:MyTemplateSelector.SecondTemplate>
</local:MyTemplateSelector>
And use it in your ListView:
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="ComponentID: " FontWeight="Bold" Foreground="Brown" />
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<ItemsControl ItemsSource="{Binding Parameters}" ItemTemplateSelector="{StaticResource itemTemplateSelector}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

List Under ListView Item

I have listview that binding with observable Collection, this listview show the invoice items, any item in invoice maybe has a sub detail (Options), (for example item color),
what i want to ask about is: how to make list view show the item options as list under the main item in listview, i hope my question is clear .. for more clarity look at the image :
What i want is in a yellow color, how to make listview look like the image ?
here's my invoice listview code :
<ListView x:Name="temsReceipt" ItemsSource="{Binding ocItemsReceipt}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="40" Width="50"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Name" Width="230" DisplayMemberBinding="{Binding ItemName}"/>
<GridViewColumn Header="Item Price" Width="100" DisplayMemberBinding="{Binding ItemPrice}"/>
</GridView>
</ListView.View>
The same think if i used the datagrid
Let's say that you have following classes:
class InvoiceItem
{
public string ItemName { get; set; }
public List<InvoiceOption> Options { get; set; }
}
class InvoiceOption
{
public string OptionName { get; set; }
}
ListView solution:
<ListView x:Name="temsReceipt" ItemsSource="{Binding}">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="40" Width="50"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Name" Width="230" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding ItemName}" VerticalAlignment="Center"
FontWeight="Bold" FontSize="18"/>
<ListBox ItemsSource="{Binding Options}" Grid.Row="1" Background="Yellow"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OptionName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Price" Width="100" DisplayMemberBinding="{Binding ItemPrice}"/>
</GridView>
</ListView.View>
</ListView>
If you want to use DataGrid you can use RowDetailsTemplate:
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding ItemName}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Margin="2" Background="Yellow">
<TextBlock Text="Options:" />
<ListBox ItemsSource="{Binding Options}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OptionName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Sample data:
...
public MainWindow()
{
InitializeComponent();
List<InvoiceItem> _source = new List<InvoiceItem>
{
new InvoiceItem
{
ItemName = "Item1",
Options = new List<InvoiceOption>
{
new InvoiceOption { OptionName = "Option1" },
new InvoiceOption { OptionName = "Option2" }
}
},
new InvoiceItem
{
ItemName = "Item2",
Options = new List<InvoiceOption>
{
new InvoiceOption { OptionName = "Option3" },
new InvoiceOption { OptionName = "Option4" }
}
}
};
this.DataContext = _source;
}
...
ListView result:

Set combobox display text to a property of ObservableCollection<T>

I have the following collection which i would like to bind to a combobox:
public ObservableCollection<Parameter> Values
{ get; set; }
public class Parameter
{
public String Text { get; set; }
public String Value { get; set; }
}
I need to bind the display text of the combobox to the Text property of the Parameter class, I've tried the following ways below but all to no avail:
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Parameter.Text"
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Parameter\Text"
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text"
When I try the 3 methods above the [assembly name].Parameter is displayed in the combobox for each parameter.
The 2 methods above don't display anything in the combobox
<ComboBox ItemsSource="{Binding Values, Path=Text}"
<ComboBox ItemsSource="{Binding Values, Path=Values.Text}"
And this one takes the text of the first parameter,splits it into characters and displays each character as a seperate item in the combobox:
<ComboBox ItemsSource="{Binding Values, Path=Values/Text}"
UPDATE:
This is the complete XAML code as requested
<ListBox BorderBrush="{x:Null}" Grid.Column="0" Height="100" Grid.ColumnSpan="2" Grid.Row="1" ItemsSource="{Binding ItemParams}" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="2" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Margin="2" Text="{Binding Name}" Background="{Binding ElementName=cmbColors, Path=SelectedItem}"/>
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text" SelectedIndex="0" HorizontalAlignment="Left" Grid.Column="1" Margin="2" Width="150" Name="cmbColors" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Grid.Column="1" Margin="2, 1" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Params class:
public class Params
{
public Params(String name, ObservableCollection<Parameter> values)
{
Name = name;
Values = values;
}
public String Name
{ get; set; }
public ObservableCollection<Parameter> Values
{ get; set; }
}
The correct formulation is one of those you already mention:
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text"
Please check again, and if it does not work post the XAML that you have verbatim.
You can do directly :
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text" />
For WPF every element of the ComboBox (ComboBoxItem) is a of type T, thus it will look for public properties on the T, this why just putting Text will work.
Had to simply remove the combobox item template or set Text="{Binding Text}"
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Grid.Column="1" Margin="2, 1" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>

Binding ListView

I have a ListView with the following code:
<ListView Name="ListView1">
<ListView.View>
<GridView>
<GridViewColumn Header="File" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="28" Height="28" Source="{Binding Icon}" Name="img"/>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding File}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Type" Width="70" DisplayMemberBinding="{Binding Type}"/>
<GridViewColumn Header="Password" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Width="145" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Can someone tell me how can I add items in it during run time and set all the bindings (Icon,File,Type)?
You create a class like:
class MyData
{
public string File { get; set; }
public string Icon { get; set; } // a path to an Icon
...
}
and then you use (in for example Window_Loaded) an
ObservableCollection<MyData> data = new ObservableCollection<MyData>();
listView1.Items = data;
data.Add(new MyData { File="text", ... });

Categories

Resources