bind List<string> to GridViewColumn - wpf

I have a GridView like following.
<Grid>
<ListView Margin="8,44,8,50" TabIndex="57" Name="CustomFieldList">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Semester Name" Width="120" DisplayMemberBinding="{Binding FieldName}"/>
<GridViewColumn Header="Subjects" Width="150" DisplayMemberBinding="{Binding TypeValidations}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
My class is;
public class DigreePrograme
{
public string semester{ get; set; }
public List<string> subjects { get; set; }
}
I have an observer collection and I have bound that to list.
static ObservableCollection<DigreePrograme> digreeList = new ObservableCollection<DigreePrograme>();
public ObservableCollection<DigreePrograme> DigreeList
{
get { return digreeList }
set { digreeList = value; OnPropertyChanged("DigreeList"); }
}
on the FormFoad
CustomFieldList.ItemsSource=DigreeList;
Issue
semester property displays perfectly. But Subject List not. It displys as Collection. How to fix this?

You could add a ItemsControl in a DataTemplate in your GridViewColumn to show all the Subject items
xaml:
<Window x:Class="WpfApplication11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="275" Width="275" x:Name="UI">
<Grid>
<ListView Name="CustomFieldList" ItemsSource="{Binding ElementName=UI, Path=DigreeList}" >
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Semester Name" Width="120" DisplayMemberBinding="{Binding Semester}"/>
<GridViewColumn Header="Subjects" Width="150" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Subjects}" Width="150" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DigreeList.Add(new DigreePrograme { Semester = "Semester 1", Subjects = new List<string>(new string[] {"Math","Art","Engish" }) });
}
private ObservableCollection<DigreePrograme> digreeList = new ObservableCollection<DigreePrograme>();
public ObservableCollection<DigreePrograme> DigreeList
{
get { return digreeList; }
set { digreeList = value;}
}
}
public class DigreePrograme
{
public string Semester { get; set; }
public List<string> Subjects { get; set; }
}
result:

I would suggest you create a new string property on your view model that would just concatenate your collection and return that. It would be the simplest way to go about this..
public class DigreePrograme
{
public string semester { get; set; }
public List<string> subjects { get; set; }
public string SubjectsDisplay
{
get
{
string returnVal = string.Empty;
foreach (string subject in subjects)
{
returnVal += subject + ", ";
}
return returnVal.TrimEnd(',', ' ');
}
}
}
something like that may help.
obviously change your binding also :)
cheers.
ste.

Related

WPF ListView - column header not as property, but as Key of Dictionary (Dictionary is ListViewItem property) - ComparisionMatrixControl

I would like to make a MatrixControl in my WPF app. First thing it starts from ListView and defines 'MatrixLine' in the model. ListView ItemsSource was an ObservableCollection. I have a simple complete model that shows what I'm aiming for and a picture with the result I expect for the created model.
I have a problem with how to add the 'MatrixLine' property type of Dictionary, [Keys] as a columns header in the ListView and [Values] (boolean) as a sign 'x' on te ListView. (The picture with the result that follows)
Expected result for my model
Result for my model creating in ViewModel constructor
GitHub Project
https://github.com/Varran/WPF_Multiporownywarki_Baza
Model
public class ColorBase
{
public string Name { get; }
public int Saturation { get; private set; }
public ColorBase(string name, int saturation)
{
this.Name = name;
this.Saturation = saturation;
}
public void ChangeSaturation(int newSaturation)
{
Saturation = newSaturation;
}
public override string ToString()
{
return $"ColorBase: {Saturation.ToString().PadLeft(4, ' ')} - '{Name}'";
}
}
public class MixedPaint
{
public string PaintName { get; }
public List<ColorBase> Ingredients { get; }
public MixedPaint(string name)
{
Ingredients = new List<ColorBase>();
this.PaintName= name;
}
public MixedPaint AddIngredient(ColorBase color)
{
bool added = false;
foreach (var item in Ingredients)
{
if (item.Name == color.Name )
{
item.ChangeSaturation(item.Saturation + color.Saturation);
added = true;
}
}
if (!added)
Ingredients.Add(color);
return this;
}
}
public class MatrixLine
{
public ColorBase ColorIngredient { get; private set; }
public Dictionary<string, bool> Matrix;
public MatrixLine(ColorBase color)
{
Matrix = new Dictionary<string, bool>();
this.ColorIngredient = color;
}
public void AddToMatrix(MixedPaint mixedPaint)
{
string paintName = mixedPaint.PaintName;
bool doesItContainIgredient = mixedPaint.Ingredients.Any(o => (o.Name == ColorIngredient.Name &&
o.Saturation == ColorIngredient.Saturation));
Matrix.Add(paintName, doesItContainIgredient);
}
}
ViewModel
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<MixedPaint> mixedPaints;
public ObservableCollection<MixedPaint> MixedPaints { get { return mixedPaints; } }
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
private MixedPaint selectedMixedPaint;
public MixedPaint SelectedMixedPaint {
get { return selectedMixedPaint; }
set { selectedMixedPaint = value;
OnPropertyChanged(nameof(SelectedMixedPaint)); } }
private ObservableCollection<MatrixLine> comparisonMatrix;
public ObservableCollection<MatrixLine> ComparisonMatrix { get { return comparisonMatrix; } }
public ViewModel()
{
ColorBase yellowA = new ColorBase("YellowA", 110);
ColorBase yellowB = new ColorBase("YellowB", 175);
ColorBase blueA = new ColorBase("BlueA", 77);
ColorBase blueB = new ColorBase("BlueB", 135);
ColorBase redA = new ColorBase("RedA", 95);
ColorBase redB = new ColorBase("RedB", 225);
ColorBase whiteA = new ColorBase("WhiteA", 200);
MixedPaint greenA = new MixedPaint("GreenLight")
.AddIngredient(yellowA)
.AddIngredient(blueA);
MixedPaint greenB = new MixedPaint("GreenDark")
.AddIngredient(yellowB)
.AddIngredient(blueB);
MixedPaint orangeA = new MixedPaint("OrangeLight")
.AddIngredient(yellowA)
.AddIngredient(redB)
.AddIngredient(whiteA);
MixedPaint orangeB = new MixedPaint("OrangeDark")
.AddIngredient(yellowB)
.AddIngredient(redB);
MixedPaint violet = new MixedPaint("Violet")
.AddIngredient(redA)
.AddIngredient(blueB);
mixedPaints = new ObservableCollection<MixedPaint>() { greenA, greenB, orangeA, orangeB, violet };
SelectedMixedPaint = greenA;
List<ColorBase> uniqueColorsBase = new List<ColorBase>();
foreach (var item in mixedPaints)
foreach (var item2 in item.Ingredients)
if (!uniqueColorsBase.Contains(item2))
uniqueColorsBase.Add(item2);
uniqueColorsBase = uniqueColorsBase.OrderBy(o => o.Name).ThenBy(o => o.Saturation).ToList();
comparisonMatrix = new ObservableCollection<MatrixLine>();
foreach (var color in uniqueColorsBase)
{
MatrixLine line = new MatrixLine(color);
foreach (var mixed in mixedPaints)
line.AddToMatrix(mixed);
comparisonMatrix.Add(line);
}
}
}
View
<Window x:Class="WPF_multi_próby.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_multi_próby"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Name="ListOfMixedPaint"
Grid.Row="0" Grid.Column="0" Orientation="Vertical">
<TextBlock Text="List of MixedPaint:"/>
<ListView ItemsSource="{Binding MixedPaints}" SelectedItem="{Binding SelectedMixedPaint}" Margin="10">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="PaintName: "/>
<TextBlock Text="{Binding PaintName}" Width="120" FontWeight="Bold"/>
<TextBlock Text="IngradientCount: " Margin="0,0,10,0"/>
<TextBlock Text="{Binding Ingredients.Count}" FontWeight="Bold"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<StackPanel Name="BOM"
Grid.Column="1" Grid.Row="0">
<TextBlock Text="Ingredients of selected MixedPaint"/>
<ListView ItemsSource="{Binding SelectedMixedPaint.Ingredients}" Margin="10">
<ListView.View>
<GridView>
<GridViewColumn Header="Color Name" DisplayMemberBinding="{Binding Name}" Width="100"/>
<GridViewColumn Header="Color Saturation" DisplayMemberBinding="{Binding Saturation}" Width="100"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
<StackPanel Name="MultiComparerOfPaints"
Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Orientation="Vertical">
<TextBlock Text="Multicomparer of paints"/>
<ListView ItemsSource="{Binding ComparisonMatrix}" Margin="10" FontFamily="Cascadia Code" >
<ListView.View>
<GridView>
<GridViewColumn Header="Unique ingredient" DisplayMemberBinding="{Binding ColorIngredient}" Width="180"/>
<!-- no idea how binding -->
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Grid>
</Window>
I think this is my solution.
I do not fully understand this solution yet, but I will have to try.
DataMatrix in WPF - codeproject
or
Binding matrix arrays to WPF DataGrid

Can't get Dictionary<> (Or ObservableCollection<KVP>) to bind to ListView

I am trying to get a Dictionary to bind to a ListView. Having not worked, I changed the Datatype to ObservableCollection> but still no joy. I know I'm missing something silly but....
The data is readonly, meaning that the UI will not update it, only the code behind.
The XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<ListView Grid.Column="1" Background="Orange" ItemsSource="{Binding MyItems}">
<ListView.View>
<GridView>
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Key}"/>
<GridViewColumn Header="Quantity" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
The DataObject:
public ObservableCollection<KeyValuePair<string, int>> MyItems{ get; set; }
And the assignment:
this.MyItems = new ObservableCollection<KeyValuePair<string, int>>(
PIData.GetNeededItems(itemName));
You should assign the MyItems property before InitializeComponent is called.
public MainWindow()
{
MyItems = new ObservableCollection<KeyValuePair<string, int>>(
PIData.GetNeededItems(itemName));
InitializeComponent();
}
If that is not possible, implement INotifyPropertyChanged:
public partial class MainWindow : Window, INotifyPropertyChanged
{
...
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<KeyValuePair<string, int>> myItems;
public ObservableCollection<KeyValuePair<string, int>> MyItems
{
get { return myItems; }
set
{
myItems = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(MyItems)));
}
}
}

Binding more properties into GridViewColumnHeader

I would like to make GridView with column header, for example like exampe below (example for one column). My DataTemplate for header contains have more controls (TextBlock and TextBox) and I am not able to figure out how to set binding to access individual controls from template (header). In my example, instead of "aaa" to set value of HColumn1Line2 property.
<ListView Name="PeopleList" ItemsSource="{Binding People}">
<ListView.Resources>
<DataTemplate x:Key="MyHeaderTemplate">
<StackPanel>
<TextBlock Text="{Binding}"/>
<TextBox Text="aaa"></TextBox>
</StackPanel>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView ColumnHeaderTemplate="{StaticResource MyHeaderTemplate}">
<GridViewColumn Header="{Binding HColumn1Line1}" DisplayMemberBinding="{Binding PeopleListItem}"/>
</GridView>
</ListView.View>
</ListView>
//Code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PeopleList.DataContext = this;
_people.Add(new Person() { PeopleListItem = "some information" });
HColumn1Line1 = "Header line #1";
HColumn1Line2 = "text instead of aaa";
}
public List<Person> People { get { return _people; } }
List<Person> _people = new List<Person>();
public string HColumn1Line1 { get; set; }
public string HColumn1Line2 { get; set; }
}
public class Person
{
public string PeopleListItem { get; set; }
}
The main problem you have is you are using the MainWindow instance as DataContext for the ListView which is in the MainWindow Content this will run you into exceptions such as "Logical tree depth exceeded while traversing the tree.", so you better make your DataContext a seperate object such as the following:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PeopleList.DataContext = new ViewModel();
}
}
public class ViewModel
{
public List<Person> People { get { return _people; } }
List<Person> _people = new List<Person>();
public string HColumn1Line1 { get; set; } = "Header line #1";
public string HColumn1Line2 { get; set; } = "text instead of aaa";
public ViewModel()
{
_people.Add(new Person() { PeopleListItem = "some information" });
}
}
public class Person
{
public string PeopleListItem { get; set; }
}
Updated XAML:
<ListView Name="PeopleList" ItemsSource="{Binding People}">
<ListView.Resources>
<DataTemplate x:Key="MyHeaderTemplate">
<StackPanel>
<TextBlock Text="{Binding HColumn1Line1}"/>
<TextBox Text="{Binding HColumn1Line2}"></TextBox>
</StackPanel>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView ColumnHeaderTemplate="{StaticResource MyHeaderTemplate}">
<GridViewColumn Header="{Binding}" DisplayMemberBinding="{Binding PeopleListItem}"/>
</GridView>
</ListView.View>
</ListView>

WPF Binding sub class to Listview

I have this class:
public class Car
{
public struct CarType
{
public string Manufacturer { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}
public CarType Type;
public string LicenseNumber { get; set; }
public int Km { get; set; }
}
To bind LicenseNumber or Km to my listview, I use:
<ListView.View>
<GridView>
<GridViewColumn Width="140" DisplayMemberBinding="{Binding LicenseNumber}">
<GridViewColumn.Header>
<GridViewColumnHeader Click="GridViewColumnHeader_Click">License Number</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
</GridView>
</ListView.View>
The command DisplayMemberBinding="{Binding LicenseNumber}" binds to LicenseNumber property.
But how to bind sub-class. like Type.Manufacturer? Type.Model?
You can bind to properties on instances as well (just use the dot notation that you are already familiar with):
<TextBlock Text="{Binding Path=Type.Manufacturer}" />
You probably never tried.
<GridViewColumn Width="140" DisplayMemberBinding="{Binding Type.Manufacturer}">
You should using following code:
<ListView.View>
<GridView>
<GridViewColumn Width="140" DisplayMemberBinding="{Binding Type.Manufacturer}">
...

DataTemplate disappears when moving items in ObservableCollection

I have a CellTemplate for a column in a ListView. The CellTemplate contains a ComboBox which has an ItemTemplate. Both ItemsSource and SelectedItem is bound to another ViewModel.
The ListView is bound to an ObservableCollection on a ViewModel. Above the ListView there is a toolbar with the buttons to move the selected item up and down. I buttons a bound to and ICommand which will make a Move on the ObservableCollection.
The view is updated fine, but the selected item in the ComboBox is not using the DataTemplate and is just showing the type name.
I found out that everything is working fine if IsEditable = false, but I need this to be true.
I have created a small project that verifies the problem. Perhaps this is an issue in WPF.
Here is XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type WpfApplication3:Item}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="cellTemplate">
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" Width="100" IsEditable="true" TextSearch.TextPath="Name"/>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ToolBar>
<Button Content="Add" Command="{Binding AddItemCommand}"/>
<Button Content="Up" Command="{Binding MoveItemUpCommand}" CommandParameter="{Binding ElementName=listView, Path=SelectedItem}"/>
<Button Content="Down" Command="{Binding MoveItemDownCommand}" CommandParameter="{Binding ElementName=listView, Path=SelectedItem}"/>
</ToolBar>
<ListView x:Name="listView" ItemsSource="{Binding Collection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" CellTemplate="{StaticResource cellTemplate}"/>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel
{
public ICommand AddItemCommand { get; private set; }
public ICommand MoveItemUpCommand { get; private set; }
public ICommand MoveItemDownCommand { get; private set; }
public ObservableCollection<Row> Collection { get; set; }
public ViewModel()
{
Collection = new ObservableCollection<Row>();
AddItemCommand = new RelayCommand(AddItem);
MoveItemUpCommand = new RelayCommand<Row>(MoveItemUp, CanMoveItemUp);
MoveItemDownCommand = new RelayCommand<Row>(MoveItemDown, CanMoveItemDown);
}
private bool CanMoveItemDown(Row arg)
{
if (arg == null)
return false;
return Collection.Last() != arg;
}
private void MoveItemDown(Row obj)
{
var index = Collection.IndexOf(obj);
Collection.Move(index, index + 1);
}
private bool CanMoveItemUp(Row arg)
{
if (arg == null)
return false;
return Collection.First() != arg;
}
private void MoveItemUp(Row row)
{
var index = Collection.IndexOf(row);
Collection.Move(index, index - 1);
}
private void AddItem()
{
Collection.Add(new Row());
}
}
public class Row
{
public Row()
{
Items = new List<Item> { new Item { Name = "Test1" }, new Item { Name = "Test2" } };
}
public List<Item> Items { get; set; }
public Item SelectedItem { get; set; }
}
public class Item
{
public string Name { get; set; }
public int Order { get; set; }
}

Resources