ObservableCollection<T> doesn't update the GUI - c#

I really don't know how to get this working. I have an ObservableCollection with "BackupItems" in it. This collection is shown in a ListView. When I add/remove or change the "BackupItems" the User Interface doesn't update! Can you help me please? Have I set the Binding wrong? :(
This is my code: (shortened to the relevant things)
BackupWindow XAML:
<ListView ItemsSource="{Binding Path=BackupItems}" SelectedItem="{Binding Path=SelectedBackupItem}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Name}"></TextBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Location">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding Path=Location"} />
<Button Grid.Column="1" Content="Browse..." Click="BrowseButton_Click"></Button>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Date of last Backup" DisplayMemberBinding="{Binding Path=LastBackup}" />
<GridViewColumn Header="Date Created" DisplayMemberBinding="{Binding Path=Created}" />
<GridViewColumn Header="Date Modified" DisplayMemberBinding="{Binding Path=Modified}" />
</GridView>
</ListView.View>
</ListView>
Code Behind:
public partial class BackupWindow : Window
{
public BackupWindow()
{
InitializeComponent();
BackupViewModel backupViewModel = new BackupViewModel();
DataContext = backupViewModel;
}
private void CreateBackupItemButton_Click(object sender, RoutedEventArgs e)
{
BackupViewModel backupViewModel = (BackupViewModel)DataContext;
BackupItem newBackupItem = new BackupItem();
newBackupItem.Created = DateTime.Now;
newBackupItem.Modified = DateTime.Now;
newBackupItem.Name = "";
newBackupItem.Location = "";
backupViewModel.BackupItems.Add(newBackupItem);
}
private void DeleteBackupItemButton_Click(object sender, RoutedEventArgs e)
{
BackupViewModel backupViewModel = (BackupViewModel)DataContext;
backupViewModel.BackupItems.Remove(backupViewModel.SelectedBackupItem);
}
private void BrowseButton_Click(object sender, RoutedEventArgs e)
{
UIElement browseButton = (UIElement)sender;
DependencyObject grid = VisualTreeHelper.GetParent(browseButton);
DependencyObject currentbackupItem = VisualTreeHelper.GetParent(grid);
System.Windows.Controls.ContentPresenter a = (System.Windows.Controls.ContentPresenter)currentbackupItem;
BackupItem currentBackupItem = (BackupItem)a.Content;
BackupViewModel backupViewModel = (BackupViewModel)DataContext;
// The VistaFolderBrowserDialog is from "Ooki.Dialogs"
VistaFolderBrowserDialog folderBrowserDialog = new VistaFolderBrowserDialog();
bool? result = folderBrowserDialog.ShowDialog();
if (result == true) // If the user presses Open in the dialog
{
// Find the currentBackupItem in the List
for (int i = 0; i < backupViewModel.BackupItems.Count; i++)
{
if (currentBackupItem == backupViewModel.BackupItems[i])
{
backupViewModel.BackupItems[i].Location = folderBrowserDialog.SelectedPath;
backupViewModel.BackupItems[i].Modified = DateTime.Now;
break;
}
}
}
}
}
ViewModel
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
BackupViewModel:
public class BackupViewModel : ViewModel
{
public ObservableCollection<BackupItem> BackupItems
{
get
{
return BackupItemLibrary.GetInstance().BackupItems;
}
}
}
BackupItemLibrary
public class BackupItemLibrary
{
private static BackupItemLibrary instance;
public static BackupItemLibrary GetInstance()
{
if (instance == null)
{
instance = new BackupItemLibrary();
}
return instance;
}
public static void SetInstance(BackupItemLibrary newBackupItemLibrary)
{
instance = newBackupItemLibrary;
}
private BackupItemLibrary()
{
}
public string FileName { get; set; }
private ObservableCollection<BackupItem> backupItems = new ObservableCollection<BackupItem>();
public ObservableCollection<BackupItem> BackupItems
{
get
{
return backupItems;
}
set
{
backupItems = value;
}
}
BackupItem:
public class BackupItem
{
public string Name { get; set; }
public string Location { get; set; }
public DateTime LastBackup { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
The solution for the problem:
Class BackupItem must implement INotifyPropertyChanged (e.g by also deriving from ViewModel), and fire the PropertyChanged event when a property value is set (at least when the Location or Modified properties are set).
Code:
public class BackupItem : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
}
}
private string location;
public string Location
{
get
{
return location;
}
set
{
location = value;
OnPropertyChanged("Location");
}
}
private DateTime lastBackup;
public DateTime LastBackup
{
get
{
return lastBackup;
}
set
{
lastBackup = value;
OnPropertyChanged("LastBackup");
}
}
private DateTime created;
public DateTime Created
{
get
{
return created;
}
set
{
created = value;
OnPropertyChanged("Created");
}
}
private DateTime modified;
public DateTime Modified
{
get
{
return modified;
}
set
{
modified = value;
OnPropertyChanged("Modified");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Related

Displaying Empty Combobox content in DataGridView?

I created a User Control page (SubPODetailView.xaml) that contains some entities "that entities defined from SubPO.cs" and a datagridview "that gridview is a separated class called SubInvoice.cs", and everything went good but in the datagridview, one of entities is a combobox display, the problem here is the collection list of this combobox is not displayed when running a program.
SubPO.cs
public class SubInvoice
{
public int Id { get; set; }
[Required]
public string InvoiceName { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public List<string> Status{ get; set; }
public int SubPOId { get; set; }
public SubPO SubPO { get; set; }
}
Configuration.cs (In Migration Folder)
context.SubInvoices.AddOrUpdate(i => i.InvoiceName,
new SubInvoice
{
InvoiceName = "Invoice1",
Date = new DateTime(2020, 5, 26),
Amount = 1200,
SubPOId=context.SubPOs.First().Id,
Status = new List<string>() { "Open", "Closed", "Pending" }
});
SubPODetailViewModel.cs
<DockPanel Grid.Row="12" Margin="10">
<StackPanel DockPanel.Dock="Right" Width="86">
<Button Content="Add" Margin="10"
Command="{Binding AddInvoiceCommand}"/>
<Button Content="Remove" Margin="10"
Command="{Binding RemoveInvoiceCommand}"/>
</StackPanel>
<DataGrid ItemsSource="{Binding Invoices}"
SelectedItem="{Binding SelectedInvoice,Mode=TwoWay}"
AutoGenerateColumns="False" RowHeaderWidth="0" >
<DataGrid.Columns>
<DataGridTextColumn Header="Invoices" Width="*"
Binding="{Binding InvoiceName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTemplateColumn Header="Status" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Date,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Amount" Width="*" Binding="{Binding Amount,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTemplateColumn Header="Status" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Status,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
SubPODetailViewModel.cs(Model)
namespace SubBV.UI.ViewModel
{
public class SubPODetailViewModel : DetailViewModelBase, ISubPODetailViewModel
{
private ISubPORepository _subPORepository;
private IMessageDialogService _messageDialogService;
private SubPOWrapper _subPO;
private SubInvoiceWrapper _selectedInvoice;
public SubPODetailViewModel(IEventAggregator eventAggregator,
IMessageDialogService messageDialogService,
ISubPORepository subPORepository) : base(eventAggregator)
{
_subPORepository = subPORepository;
_messageDialogService = messageDialogService;
AddInvoiceCommand = new DelegateCommand(OnAddInvoiceExecute);
RemoveInvoiceCommand = new DelegateCommand(OnRemoveInvoiceExecute, OnRemoveInvoiceCanExecute);
Invoices = new ObservableCollection<SubInvoiceWrapper>();
}
public SubPOWrapper SubPO
{
get { return _subPO; }
private set
{
_subPO = value;
OnPropertyChanged();
}
}
public SubInvoiceWrapper SelectedInvoice
{
get { return _selectedInvoice; }
set
{
_selectedInvoice = value;
OnPropertyChanged();
((DelegateCommand)RemoveInvoiceCommand).RaiseCanExecuteChanged();
}
}
public ICommand AddInvoiceCommand { get; }
public ICommand RemoveInvoiceCommand { get; }
public ObservableCollection<SubInvoiceWrapper> Invoices { get; }
public override async Task LoadAsync(int? subPOId)
{
var subPO = subPOId.HasValue
? await _subPORepository.GetByIdAsync(subPOId.Value)
: CreateNewSubPO();
InitializeSubInvoice(subPO.Invoices);
}
private void InitializeSubInvoice(ICollection<SubInvoice> invoices)
{
foreach (var wrapper in Invoices)
{
wrapper.PropertyChanged -= SubInvoiceWrapper_PropertyChanged;
}
Invoices.Clear();
foreach (var subInvoice in invoices)
{
var wrapper = new SubInvoiceWrapper(subInvoice);
Invoices.Add(wrapper);
wrapper.PropertyChanged += SubInvoiceWrapper_PropertyChanged;
}
}
private void SubInvoiceWrapper_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!HasChanges)
{
HasChanges = _subPORepository.HasChanges();
}
if (e.PropertyName == nameof(SubInvoiceWrapper.HasErrors))
{
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
}
}
private void InitializeSubPO(SubPO subPO)
{
SubPO = new SubPOWrapper(subPO);
SubPO.PropertyChanged += (s, e) =>
{
if (!HasChanges)
{
HasChanges = _subPORepository.HasChanges();
}
if (e.PropertyName == nameof(SubPO.HasErrors))
{
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
}
};
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
if (SubPO.Id == 0)
{
// Little trick to trigger the validation
SubPO.Title = "";
}
}
}
SubInvoiceWrapper.cs (Wraps what is contained in the DataGridView)
public class SubInvoiceWrapper:ModelWrapper<SubInvoice>
{
public SubInvoiceWrapper(SubInvoice model) : base(model)
{
}
public string InvoiceName
{
get { return GetValue<string>(); }
set { SetValue(value); }
}
public DateTime Date
{
get { return GetValue<DateTime>(); }
set { SetValue(value); }
}
public decimal Amount
{
get { return GetValue<decimal>(); }
set { SetValue(value); }
}
public List<string> Status
{
get { return GetValue<List<string>>(); }
set { SetValue(value); }
}
}
ViewModelBase.cs (contains the propertychanged)
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Databinding an Object Type to ListViewColumns

Good day,
I am trying to Bind data to my ListView Columns and I am having trouble.
public partial class ListViewItem
{
public object Tag
{
get { return _tag; }
set
{
if (value == _tag) return;
_tag = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
This Tag Property is set to be a List<ActionObject> For simplicity sake, i'll just post the class with one variable in it.
public class ActionObject : INotifyPropertyChanged
{
private string _command;
public string Command
{
get { return _command; }
set
{
if (value == _command) return;
_command = value;
OnPropertyChanged();
}
}
}
Here is the XAML Code
<ListView x:Name="ActionLV" ItemsSource="{Binding ActionData.ListViewCollection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Command" DisplayMemberBinding="{Binding Tag.Command, UpdateSourceTrigger=PropertyChanged}"/>
</GridView>
</ListView.View>
</ListView>
In the image below you can see that ListViewCollection is being populated, but its not updating.
private ObservableCollection<ListViewItem> _listViewCollection;
public ObservableCollection<ListViewItem> ListViewCollection
{
get { return _listViewCollection; }
set
{
if (value == _listViewCollection) return;
_listViewCollection = value;
OnPropertyChanged();
}
}

update listbox item when item is tapped

I have a listbox wit listboxitems with an image and a textblock.
The listbox has a custom class as datasource.
What I want is when the listboxItem is tapped. The image inside the listboxitem changes.
Here is what I have so far:
My custom class:
public class MemberUser
{
[JsonProperty("member_id", NullValueHandling = NullValueHandling.Ignore)]
public int member_id { get; private set; }
[JsonProperty("first_name", NullValueHandling = NullValueHandling.Ignore)]
public String first_name { get; private set; }
[JsonProperty("last_name", NullValueHandling = NullValueHandling.Ignore)]
public String last_name { get; private set; }
public string fullName
{
get
{
return String.Format("{0} {1}", first_name, last_name);
}
}
public bool selected{get;set;}
public string selectedImage
{
get{
if (selected)
{
return "/Assets/ic_selected.png";
}
else
{
return "/Assets/ic_not_selected.png";
}
}
}
}
My codebehind file (Only the code that you need to understand)
private OrganizationObject community;
private IEnumerable<MemberUser> memItems;
private List<MemberUser> notFoundEvents = new List<MemberUser>();
public EventAdd()
{
InitializeComponent();
BindData();
}
private async void BindData()
{
try
{
memItems = MemberDataSource.memberList;
if (memItems.Count() == 0)
{
await MemberDataSource.GetLocalMember();
memItems = MemberDataSource.memberList;
}
inviteList.DataContext = memItems;
/* foreach (MemberUser obj in memItems)
{
if (obj.accepted == 1)
{
inviteList.Items.Add(obj);
}
}*/
}
catch (KeyNotFoundException)
{
NavigationService.GoBack();
}
}
private void Selectionchanged_Eventhandler_of_Listbox(object sender, SelectionChangedEventArgs e)
{
MemberUser myobject = (sender as ListBox).SelectedItem as MemberUser;
if (myobject.selected)
{
myobject.selected = false;
}
else
{
myobject.selected = true;
}
}
My XAML
<ListBox x:Name="inviteList" ItemsSource="{Binding}" Margin="20,0,0,0" SelectionChanged="Selectionchanged_Eventhandler_of_Listbox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="80" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="0.70*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.Row="0" x:Name="img_selected" Source="{Binding selectedImage}" Width="26" Height="29"></Image>
<TextBlock Grid.Column="1" Grid.Row="0" x:Name="fullName" Text="{Binding fullName}" Foreground="#FF4C6383" FontFamily="/Membr;component/Assets/Fonts/Fonts.zip#Source Sans Pro" Height="50" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So what am i missing? Also it seems like I can only tap once on each list item?
Please help !
You can achieve it with few ways:
1) Inherit you custom class from INotifyPropertyChanged
public class MemberUser : INotifyPropertyChanged
{
public int member_id { get; private set; }
public String first_name { get; private set; }
public String last_name { get; private set; }
public string fullName
{
get
{
return String.Format("{0} {1}", first_name, last_name);
}
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged("selectedImage");
}
}
private bool _isSelected;
public string selectedImage
{
get
{
if (IsSelected)
{
return "/Assets/ic_selected.png";
}
else
{
return "/Assets/ic_not_selected.png";
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
2) Bind ImageSource to IsSelected property through Converter
<Image Grid.Column="0" Grid.Row="0" x:Name="img_selected" Source="{Binding IsSelected, Converter={StaticResource SelectedImageConverter}}" Width="26" Height="29"></Image>
public class SelectedImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
var isSelected = (bool)value;
return isSelected
? "/Assets/ic_selected.png"
: "/Assets/ic_not_selected.png";
}
catch (Exception)
{
return "/Assets/ic_not_selected.png";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
If the problem isn't the images path, I think you need to implement INotifyPropertyChanged interface, in the MemberUser class, and when you set the Selected property, notify also the change of SelectedImage property. Something like:
private bool _selected;
public bool Selected
{
get{ return _selected;}
set
{
if(value!=_selected)
{
_selected=value;
OnPropertyChanged("Selected");
OnPropertyChanged("SelectedImage");
}
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName="")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Try
public ImageSource selectedImage
{
ImageSource temp;
get{
if (selected)
{
temp=new BitmapImage(new Uri("ms-appx:////Assets/ic_selected.png", UriKind.RelativeOrAbsolute));
return temp ;
}
else
{
temp=new BitmapImage(new Uri("/Assets/ic_not_selected.png", UriKind.RelativeOrAbsolute));
return temp ;
}
}
}
Since Source of image Binds to an ImageSource not to string.
Check if your url requires ms-appx://// or not. (it does in windows 8.1 apps) Also You need to add an INotifyProperty Chaged extension to be able to see the property being changed instantly.

ItemsSource to ObservableCollection<T> doesn't refresh if change items inside it

In my application I have a datagrid which has as its ItemsSource ObservableCollection< Carrello >.
<Grid x:Name="DatiCarrello">
<DataGrid Name="carrello" RowStyle="{StaticResource RowStyleWithAlternation}" AlternationCount="2" AutoGenerateColumns="False" Margin="40,95,250,30">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID_prodotto}" />
<DataGridTextColumn Header="Descrizione" Binding="{Binding Path=Descrizione}" Width="100"/>
[...]
</DataGrid.Columns>
</DataGrid>
</Grid>
My class Carrello:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApplication1.Classi
{
class Carrello
{
public string ID_prodotto { get; set; }
public string Descrizione { get; set; }
public double Prezzo { get; set; }
public int Quantita { get; set; }
public int Sconto { get; set; }
public int Quantita_massima { get; set; }
private static ObservableCollection<Carrello> ProdottiInCarrello = new ObservableCollection<Carrello>();
public static void ClearElencoProdottiInCarrello()
{
ProdottiInCarrello.Clear();
}
public static ObservableCollection<Carrello> GetElencoProdottiInCarrello()
{
return ProdottiInCarrello;
}
public static void InserciProdottoInCarrello(Carrello items)
{
foreach (Carrello element in ProdottiInCarrello)
if (element.ID_prodotto == items.ID_prodotto)
{
element.Quantita += items.Quantita;
return;
}
ProdottiInCarrello.Add(items);
}
}
}
And this it how I use it:
public partial class FinestraCassa : UserControl
{
private Carrello prodotto_carrello = new Carrello();
public FinestraCassa()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DatiCarrello.DataContext = prodotto_carrello;
Carrello.ClearElencoProdottiInCarrello();
carrello.ItemsSource = Carrello.GetElencoProdottiInCarrello();
}
private void qta_articolo_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
int sconto = 0;
int.TryParse(sconto_articolo.Text.Replace("%", ""), out sconto);
prodotto_carrello.Sconto = sconto;
Carrello.InserciProdottoInCarrello(prodotto_carrello);
/* Pulisco per nuovo elemento */
prodotto_carrello = new Carrello();
DatiCarrello.DataContext = prodotto_carrello;
TextBoxSearch.Focus();
}
}
}
For every new product that I insert the DataGrid is properly notified, and displays the new line in it.
The problem is when I insert the same product, it should update only the amount (if it is already in the list). Effectively amount is updated, but the refresh is not performed immediately, but I have to click inside the cell "Quantity" to see the change.
Should I implement the INotifyPropertyChanged, but I can not understand how ...
In order to pick up the property changes that you make to your 'Carello' class in the background, you should implement it like this...
public class Carrello :INotifyPropertyChanged
{
private string _id_prodotto;
public string ID_prodotto
{
get { return _id_prodotto; }
set
{
if (value != _id_prodotto)
{
_id_prodotto = value;
OnPropertyChanged("ID_prodotto");
}
}
}
//
// Do the same thing for all the other public properties you are binding to
//
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = System.Threading.Interlocked.CompareExchange(ref
PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
This will raise the appropriate notification, and that will result in the behaviour you are looking for.

Update listview from code behind

I have the following code in xaml:
<ListView Name="listView1" IsSynchronizedWithCurrentItem="True" >
<ListView.View>
<GridView>
<GridViewColumn Header="MyList">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Cost, Mode=TwoWay}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
on my code behind I have:
public partial class LogIn : UserControl, INotifyCollectionChanged
{
class Product
{
public string Name { get; set; }
public int Cost { get; set; }
}
ObservableCollection<Product> MyList = new ObservableCollection<Product>()
{
new Product(){ Cost=14},
new Product(){ Cost=15},
new Product(){ Cost=5},
new Product(){ Cost=20}
};
event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
{
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
// constructor
public LogIn()
{
InitializeComponent();
listView1.DataContext = MyList;
}
private void button5_Click(object sender, RoutedEventArgs e)
{
this.MyList[0].Cost = 123456789;
// !!!!!!!!!!!!!!! I want the listview to update when I press this button
}
The listview does not change when I update on the last method. what do I have to do so that I can update the listview cost values with code behind?
Edit
Thanks to SLaks I made the following changes to my Product class and it worked.
public class Product : INotifyPropertyChanged
{
private int _cost;
public string Name { get; set; }
public int Cost
{
get
{
return _cost;
}
set
{
_cost = value;
OnPropertyChanged("Cost");
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
also I added the following line in the constructor of the usercontroll:
listView1.ItemsSource = MyList;
You need to implement INotifyPropertyChanged in the Product class so that WPF knows when your properties change.

Categories

Resources