I have 3 level subclasses with ObservableCollection<T> properties of each other. In MainViewModel I created ObservableCollection<Group> property which elements of Group class will be in first level in TreeView. In every Group class I created child ObservableCollection<Parameter> property. And in the end in Parameter class I created ObservableCollection<ParameterValue> for store values. Note: every class based on INotifyPropertyChanged interface. Let's to go the code.
Models.cs:
//BaseModel implement INotifyPropertyChanged
public class ParameterValue: BaseModel
{
private DateTime dateTimeValue;
public DateTime DateTimeValue
{
get { return dateTimeValue; }
set
{
dateTimeValue = value;
NotifyPropertyChanged("DateTimeValue");
}
}
private double value;
public double Value
{
get { return value; }
set
{
this.value = value;
NotifyPropertyChanged("Value");
}
}
}
//BaseModel implement INotifyPropertyChanged
public class Parameter: BaseModel
{
public Parameter()
{
values = new ObservableCollection<ParameterValue>();
}
private ObservableCollection<ParameterValue> values;
public ObservableCollection<ParameterValue> Values
{
get { return values; }
set
{
values = value;
NotifyPropertyChanged("Values");
}
}
private int parameterId;
public int ParameterId
{
get { return parameterId; }
set
{
parameterId = value;
NotifyPropertyChanged("ParameterId");
}
}
private string parameterName;
public string ParameterName
{
get { return parameterName; }
set
{
parameterName = value;
NotifyPropertyChanged("ParameterName");
}
}
}
//BaseModel implement INotifyPropertyChanged
public class Group: BaseModel
{
public Group()
{
parameters = new ObservableCollection<Parameter>();
}
private ObservableCollection<Parameter> parameters;
public ObservableCollection<Parameter> Parameters
{
get { return parameters; }
set
{
parameters = value;
NotifyPropertyChanged("Parameters");
}
}
private int groupId;
public int GroupId
{
get { return groupId; }
set
{
groupId = value;
NotifyPropertyChanged("Id");
}
}
private string groupName;
public string GroupName
{
get { return groupName; }
set
{
groupName = value;
NotifyPropertyChanged("GroupName");
}
}
}
//Implementing INotifyPropertyChanged
public class BaseModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModels.cs:
//BaseModel implement INotifyPropertyChanged
public class MainViewModel: BaseModel
{
public MainViewModel()
{
groups = new ObservableCollection<Group>();
//fill sample data instead of recieving from DB
for (int i = 1; i < 11; i++)
{
Group group = new Group { GroupId = i, GroupName = "Group " + i.ToString()};
groups.Add(group);
for (int j = 1; j < 11; j++)
{
Parameter param = new Parameter { ParameterId = j, ParameterName = "Parameter "+j.ToString()};
for (int k = 1; k < 51; k++)
{
ParameterValue val = new ParameterValue { DateTimeValue = DateTime.Now.AddSeconds(i*j-k), Value = (1000-k*5)/((i+j)+1)};
param.Values.Add(val);
}
group.Parameters.Add(param);
}
}
int l = 0;
}
private ObservableCollection<Group> groups;
public ObservableCollection<Group> Groups
{
get { return groups; }
set
{
groups = value;
NotifyPropertyChanged("Groups");
}
}
}
And MainWindow.xaml in View role:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="75*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="trv" Grid.Column="0" ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parameters}">
<TextBlock Text="{Binding GroupName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ParameterName}"></TextBlock>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Column="1" Background="Bisque" ItemsSource="{Binding Path=Groups.Parameters}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date Time" DisplayMemberBinding="{Binding DateTimeValue}"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
In MainViewModel I simplify data receiving from DB replacing by nested for loops with test data.
I try to make showing selected in TreeView Parameter data in ListView in MVVM way.
In DataGroup necessary to create SelectedItem property of Parameter class for more accurate data recieving from DB? Of course in MVVM way.
In your ListView ItemSource you have to bind to the Values like so...
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25*" />
<ColumnDefinition Width="75*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="trv" Grid.Column="0" ItemsSource="{Binding Groups}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parameters}">
<TextBlock Text="{Binding GroupName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ParameterName}"></TextBlock>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Column="1"
Background="Bisque"
ItemsSource="{Binding SelectedItem.Values, ElementName=trv}">
<ListView.View>
<GridView>
<GridViewColumn Header="Date Time" DisplayMemberBinding="{Binding DateTimeValue}"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
Observer how I binded to the SelectedItem of your TreeView. That selected item is expected to be the parameter which has property Values.
If you select Group than nothing will be displayed since Group does not have Values collection. Only Parameter has that.
Related
I'm working on a small WPF project,
for now it contains one window which should display as much checkboxes are many values in lists are.
For testing purposes, before I get values from database I tried something like this:
public class StatusOption
{
public string name { get; set; }
public bool IsSelected { get; set; }
}
public void GetSerialNumbers()
{
List<StatusOption> serialNumbers = new List<StatusOption>();
for(int i = 0; i<10;i++)
{
StatusOption x = new StatusOption();
x.name = "Random name" + i;
x.IsSelected = false;
serialNumbers.Add(x);
}
}
And my xaml looks like this:
<ListBox x:Name="SerialNumbersListBox"
AllowDrop="True"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding GetSerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding serialNumbers}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But unfortunatelly nothing is displayed below textbox...
But for now everything is empty, and I can not find out why..
Thanks guys
Cheers
You could not bind a method. Please use property instead.
<ListBox HorizontalAlignment="Left" Height="171" Margin="334,96,0,0" VerticalAlignment="Top" Width="248" AllowDrop="True" x:Name="SerialNumbersListBox"
ItemsSource="{Binding SerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding name}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public class SerialNumbersListBoxViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public class StatusOption
{
public string name { get; set; }
public bool IsSelected { get; set; }
}
private ObservableCollection<StatusOption> _SerialNumbers;
public ObservableCollection<StatusOption> SerialNumbers
{
get
{
return _SerialNumbers;
}
set
{
if (value != _SerialNumbers)
{
_SerialNumbers = value;
OnPropertyChanged(nameof(SerialNumbers));
}
}
}
public void GetSerialNumbers()
{
if (_SerialNumbers == null)
_SerialNumbers = new ObservableCollection<StatusOption>();
for (int i = 0; i < 10; i++)
{
StatusOption x = new StatusOption();
x.name = "Random name" + i;
x.IsSelected = false;
_SerialNumbers.Add(x);
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public SerialNumbersListBoxViewModel()
{
GetSerialNumbers();
}
}
You can refer this link for more details
Regard!
You cannot bind to methods, you can only bind to Properties or DependencyProperties.
So you need to create a Property for your serialNumbers. You should also implement INotifyPropertyChanged, so that the ListBox can know when your property changed.
public List<object> SerialNumbers
{
get => this._serialNumbersProperty;
set
{
if (!List<object>.Equals(value, this._serialNumbersProperty))
{
this._serialNumbersProperty = value;
OnPropertyChanged(nameof(this.SerialNumbers));
}
}
}
<ListBox x:Name="SerialNumbersListBox"
AllowDrop="True"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding SerialNumbers}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding name}"
IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I try to realize MVVM. TextBox text in View is Binded to property itemName in Model.
On view is DataGrid -> Binded to ViewModel.Rows property
In ViewModel on itemName on change event run async request to remote service for products, which is goes to model SugestProducts property. SugestProducts property is source for ListView items.
If products more than 0 listview open. ListView SelectedItem is Binded to model product property.
I need on product selection in list view fill itemName property from Product.name property without request to remote service. Other work good.
My model is:
public class RowDocumentSaleWraper : INotifyPropertyChanged
{
private ObservableCollection<Product> _sugestProducts;
public ObservableCollection<Product> SugestProducts
{
get
{
return _sugestProducts;
}
set
{
_sugestProducts = value;
NotifyPropertyChanged("SugestProducts");
}
}
public Product product {get; set;}
_itemName
public override string itemName
{
get
{
return itemName;
}
set
{
itemName = value;
NotifyPropertyChanged("itemName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Product:
public class Product
{
public string name{get; set;}
}
My ViewModel Is:
public class OrderViewModel : DependencyObject
{
public ObservableCollection<RowDocumentSaleWraper> Rows { get; set; }
public OrderViewModel()
{
addNewRow();
}
internal void addNewRow()
{
RowDocumentSaleWraper row = new RowDocumentSaleWraper(Order);
row.PropertyChanged += row_PropertyChanged;
Rows.Add(row);
}
void row_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
RowDocumentSaleWraper row = sender as RowDocumentSaleWraper;
if (row != null && e.PropertyName == "itemName" && !String.IsNullOrEmpty(row.itemName))
{
//get products from remote service -> source for
requestProducts(row.itemName, row);
}
}
private async void requestProducts(string searchString, RowDocumentSaleWraper row)
{
if (!String.IsNullOrEmpty(searchString))
{
var products = await requestProductsAsync(searchString);
row.SugestProducts = listToObservable(products);
}
}
}
My Xaml:
<DataGrid Grid.Row="1" Name="mainDataGrid" ItemsSource="{Binding Rows , UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Product">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBox PreviewKeyDown="TextBox_PreviewKeyDown" KeyDown="TextBox_KeyDown" Text="{Binding itemName, UpdateSourceTrigger=PropertyChanged}" MinWidth="200"/>
<ListView ItemsSource="{Binding SugestProducts, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
KeyDown="ListView_KeyDown" SelectedItem ="{Binding product, UpdateSourceTrigger=PropertyChanged}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn DisplayMemberBinding="{Binding code}"/>
<GridViewColumn DisplayMemberBinding="{Binding name}" />
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Based on the above comments, you should notify the ViewModel from the setter on itemName
public override string itemName
{
get
{
return itemName;
}
set
{
itemName = value;
NotifyPropertyChanged("itemName");
NotifyChange(itemName);
}
}
Then you'll define the event to retrieve the data
private async void NotifyChange(string name)
{
if (!String.IsNullOrEmpty(searchString))
{
var products = await requestProductsAsync(searchString);
SugestProducts = listToObservable(products);
}
}
I'm new to WPF and I noticed we can't use listview text property
listview1.SelectedItems[0].Text = textBlock.text;
But I want to change name of a selected item in my listview so I also tried
listView.SelectedItems[0] = textBlock.Text;
But that didn't work either last code also gives me an error in this line as well
textBlock.Text = myList[listView.Items.IndexOf(listView.SelectedItems[0])].ItemName;
also I have a get,set method for myList
public string ItemName { get; set; }
also the xaml code for listview
<ListView x:Name="listView" HorizontalAlignment="Left" Height="301" Margin="10,10,0,0" VerticalAlignment="Top" Width="142" IsSynchronizedWithCurrentItem="True" BorderThickness="1" Foreground="Black" SelectionChanged="listView_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="150" DisplayMemberBinding="{Binding}"/>
</GridView>
</ListView.View>
</ListView>
SelectedItems is a read-only property that's used to get the selected items of your ListView when the selection mode is set to Multiple, if you want to change some properties value in the selected ListView's Item you must do that on the SelectedItem instead, and it will be much more comfortable to you if you implement the INotifyPropertyChanged interface (to notify the UI when a property in the ListView's SelectedItem has changed), so:
define your listView in xaml, bind its ItemSource and SelectedItem
<ListView ItemsSource="{Binding ListViewCollection}" SelectedItem="{Binding SelectedListViewItem,Mode=TwoWay}" SelectionMode="Single"></ListView>
then in the codebehind (or ViewModel), define your collection and your selected item, implement the INotifypropertyChanged and set the DataContext
public partial class MainWindow : Window,INotifyPropertyChanged
{
private ObservableCollection<ListViewItemObj> _listViewCollection;
private ListViewItemObj _selectedListViewItem;
public ObservableCollection<ListViewItemObj> ListViewCollection
{
get { return _listViewCollection; }
set
{
if (Equals(value, _listViewCollection)) return;
_listViewCollection = value;
OnPropertyChanged();
}
}
public ListViewItemObj SelectedListViewItem
{
get { return _selectedListViewItem; }
set
{
if (Equals(value, _selectedListViewItem)) return;
_selectedListViewItem = value;
OnPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
To update the ListView's SelectedItem simply do that to the SelectedListViewItem property.
Update
let's say your ListView shows a collection of the following class:
public class ListViewItemObj:INotifyPropertyChanged
{
private string _name;
private string _val;
public String Name
{
get { return _name; }
set
{
if (value == _name) return;
_name = value;
OnPropertyChanged();
}
}
public String Val
{
get { return _val; }
set
{
if (value == _val) return;
_val = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
And your code behind looks like below :
public partial class MainWindow : Window,INotifyPropertyChanged
{
private ObservableCollection<ListViewItemObj> _listViewCollection = new ObservableCollection<ListViewItemObj>()
{
new ListViewItemObj(){Name = "item 1",Val = "Val1"},
new ListViewItemObj(){Name = "item 2",Val = "Val2"},
new ListViewItemObj(){Name = "item 3",Val = "Val3"},
};
private ListViewItemObj _selectedListViewItem;
public ObservableCollection<ListViewItemObj> ListViewCollection
{
get { return _listViewCollection; }
set
{
if (Equals(value, _listViewCollection)) return;
_listViewCollection = value;
OnPropertyChanged();
}
}
public ListViewItemObj SelectedListViewItem
{
get { return _selectedListViewItem; }
set
{
if (Equals(value, _selectedListViewItem)) return;
_selectedListViewItem = value;
OnPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
Here is a simple example of how to show and update the selected ListViewItem :
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView Grid.ColumnSpan="2" ItemsSource="{Binding ListViewCollection}" SelectedItem="{Binding SelectedListViewItem,Mode=TwoWay}" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="150" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Name" Width="150" DisplayMemberBinding="{Binding Val}"/>
</GridView>
</ListView.View>
</ListView>
<TextBlock Grid.Column="0" Grid.Row="1" Text="Selected Item"/>
<TextBox Grid.Column="1" Grid.Row="1" Text="{Binding SelectedListViewItem.Val,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
I am new to MVVM and WPF, I have the below model which I want to show it to user using the data binding (Code for viewmodel and xaml is also provided below). But I am not sure what is missing, because the list of users are not being shown on UI at all. Can anyone tell me which I am missing from my code?!
If instead Class of Users, I use a List from class User:
private List<User> _UsersList;
public List<User> users
{
get { return _UsersList; }
set { _UsersList = value; }
}
, then the biding works!, but if I use Users class, the binding does not work!
Model:
public class User : ObservableObject
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool IsPremiumUser { get; set; }
public string selectedItem { get; set; }
public string SelectedValue
{
get { return selectedItem; }
set
{
selectedItem = value;
// suser.age = Convert.ToInt32(value);
RaisePropertyChangedEvent("SelectedValue");
}
}
public int[] myItem { get; set; }
public int[] UserItems
{
get { return myItem; }
set { myItem = value; }
}
private SelectedUser suser = new SelectedUser();
public int selected { get; set; }
public int Selected
{
get { return selected; }
set
{
selected = value;
suser.age = Convert.ToInt32(value);
RaisePropertyChangedEvent("Selected");
}
}
}
public class Users : ObservableObject
{
private List<User> mylist = new List<User>();
private List<User> list
{
get { return mylist; }
set
{
mylist = value;
}
}
public void Add(User user)
{
this.list.Add(user);
}
public User GetById(int id)
{
return this.list.First(u => u.ID == id);
}
}
ViewModel:
public class ViewModel : ObservableObject
{
public ViewModel()
{
users = new Users();
for (int i = 0; i < 100000; ++i)
{
int[] numbers;
numbers = new int[3] { 1, 2, 3 };
var user = new User { ID = i, Name = "Name " + i.ToString(), Age = 20 + i, UserItems = numbers, SelectedValue = "0" };
if (i == 2 || i == 4)
{
user.IsPremiumUser = true;
}
users.Add(user);
}
}
private Users _UsersList;
public Users users
{
get { return _UsersList; }
set { _UsersList = value; }
}
private int _currenuser;
public int CurrentUser
{
get
{
return _currenuser;
}
set
{
_currenuser = value;
RaisePropertyChangedEvent("CurrentUser");
}
}
}
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Icon="C:\Users\maninx2\Documents\Visual Studio 2013\Projects\SampleFormMaker1\WpfApplication1\abbott_point_of_care_HuT_icon.ico"
Title="MainWindow" Height="700" Width="1249.129">
<Window.Resources>
<DataTemplate x:Key="NormalUserDataTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBox Text="{Binding SelectedValue, UpdateSourceTrigger=PropertyChanged}" Width="300" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="PremiumUserDataTemplate">
<StackPanel Background="LightBlue">
<ComboBox SelectedIndex="{Binding SelectedValue, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Name}" Width="300" ItemsSource="{Binding UserItems}"/>
</StackPanel>
</DataTemplate>
<local:PremiumUserDataTemplateSelector x:Key="myPremiumUserDataTemplateSelector" />
</Window.Resources>
<TabControl Name="TabControl1">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="General">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Height="800" Orientation="Horizontal" >
<ListView x:Name="myListView" ItemsSource="{Binding users, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemTemplateSelector="{StaticResource myPremiumUserDataTemplateSelector}" SelectedIndex="{Binding CurrentUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ListView>
<ListView x:Name="myListView1" ItemsSource="{Binding users, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" >
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Selected Values"
DisplayMemberBinding="{Binding SelectedValue}" />
</GridView>
</ListView.View>
</ListView>
<Button Content="Next"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="75"
Click="Button_Click"/>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem Header="Second Tab">
<StackPanel>
<TextBlock Name="lbl1" Text="{Binding CurrentUser, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Previous"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="75"
Click="Button_Click1"/>
</StackPanel>
</TabItem>
</TabControl>
</Window>
You are missing inheriting the Users from ObservableCollection. So, WPF engine does not know how to get the data from this class.
Update:
#user3033921: You inherited it from ObservableObject not ObservableCollection. So, the thing is if you want this class to be recognized from as a list then you would have to get that class inherited by an ICollection object and if you want that class to be observable it should be implementing both ICollection and INotifyPropertyChange. So, to #BradleyDotNet's point if you dont have any specific reason to create your own type, then just create a object of users with type ObservableCollection. If you have a specific need to have a type Users then you can derive it from ObserableCollection as recommended solution. But keep in mind you do not want to have List in the Users class anymore as your class is now by itself is a list. So, if you have any specific implementation to do like GetByID, then the class would look like:
public class Users :ObservableCollection<User>
{
public User GetById(int id)
{
return this.First(u => u.ID == id);
}
}
I have a datagrid with four columns.
<DataGrid ItemSource="{Binding MyDataSet,Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock ...../>
</DataTemplate>
</DataGridColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock ...../>
</DataTemplate>
</DataGridColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
.............
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemSource ="{Binding FirstComboBoxData }" SelectedItem="{Binding FirstComboBoxSelectedVal}"/>
</DataTemplate>
</DataGridColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DataTemplate>
<ComboBox ItemSource ="{Binding SecondComboBoxData }" SelectedItem="{Binding SecondComboBoxSelectedVal}"/>
</DataTemplate>
</DataGridColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The model class MyData is like in the following.
class MyData : ObservableObject
{
private string _code;
public string Code
{
set { _code = value ; OnPropertyChanged("Code");}
get { return _code ;}
}
private string _name;
public string Name
{
set { _name = value ; OnPropertyChanged("Name");}
get { return _name ;}
}
private List<SomeOtherClass> _firstComboBoxData;
public List<SomeOtherClass> FirstComboBoxData
{
set { _firstComboBoxData = value ; OnPropertyChanged("FirstComboBoxData");}
get { return _firstComboBoxData ;}
}
private List<SomeOtherClass> _secondComboBoxData;
public List<SomeOtherClass> SecondComboBoxData
{
set { _secondComboBoxData = value ; OnPropertyChanged("SecondComboBoxData");}
get { return _secondComboBoxData ;}
}
private SomeOtherClass _firstComboBoxSelectedVal;
public SomeOtherClass Name
{
set { _firstComboBoxSelectedVal= value ; OnPropertyChanged("FirstComboBoxSelectedVal");}
get { return _firstComboBoxSelectedVal;}
}
private SomeOtherClass _secondComboBoxSelectedVal;
public SomeOtherClass SecondComboBoxSelectedVal
{
set { _secondComboBoxSelectedVal= value ; OnPropertyChanged("SecondComboBoxSelectedVal");}
get { return _secondComboBoxSelectedVal;}
}
}
class SomeOtherClass
{
private int id;
public int ID
{
set { id = value ; OnPropertyChanged("ID");}
get { return id ;}
}
}
Then I have the following list in my ViewModel.
private ObservableCollection<MyData> _myDataSet;
public ObservableCollection<MyData> MyDataSet
{
set { _myDataSet=value; OnPropertyChanged ("MyDataSet"); }
get { return _myDataSet ;}
}
I see everything is fine. But when I change the selected item of said comboboxes, MyDataSet's relevant FirstComboBoxSelectedVal or SecondComboBoxSelectedVal is not updated
Have I done something wrong somewhere?