Reputation: 17049
I have a ListBox
which I bind to an ObservableCollection<Series>
in the view model. Everytime users click on the "Delete" button the Delete
DelegateCommand
for the specific item is executed inside the Series
class and the item is removed from the Database.
I'm looking for some way to update the ObservableCollection<Series>
when this happens so that the relevant item is removed from the XAML view as soon as it's deleted.
Currently this is not happening, I'm relatively new to WPF and have been trying to get this working for days, please suggest where I'm going wrong:
Relevant XAML:
<ListBox ItemsSource="{Binding SeriesCollection}" Name="lbSeries" Background="#6E7587" ItemContainerStyle="{StaticResource highlightStyle}" SelectionMode="Single" AlternationCount="2" Grid.Row="2" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Margin="5,0" FontSize="14" Name="txtName" Text="{Binding Name}" Width="190" Height="30" Grid.Column="0" />
<wpfToolkit:IntegerUpDown Value="{Binding Season}" Name="nudSeason" FontSize="14" Height="30" Width="95" Increment="1" Maximum="100000" Minimum="0" Grid.Column="1" />
<wpfToolkit:IntegerUpDown Value="{Binding Episode}" Name="nudEpisode" FontSize="14" Height="30" Width="95" Increment="1" Maximum="100000" Minimum="0" Grid.Column="2" />
<Button Command="{Binding Save}" Grid.Column="3" Width="60" Height="50" Cursor="Hand" ToolTip="Save program" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Image Source="Resources\Save.png" Width="30" Height="40" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Button Command="{Binding Delete}" Grid.Column="4" Width="60" Height="50" Cursor="Hand" CommandParameter="{Binding ElementName=lbSeries,Path=SelectedItem}" ToolTip="Remove program" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="15,0">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Image Source="Resources\Delete.png" Width="30" Height="40" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Label Content="{Binding Information}" Grid.Column="5" FontSize="14" Margin="10,0" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
View model:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using SeriesTracker.Functions;
using System.Linq;
namespace SeriesTracker.Client
{
public class SeriesTrackerViewModel : INotifyPropertyChanged
{
public DelegateCommand NewSeries { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Series> _series = new ObservableCollection<Series>();
public ObservableCollection<Series> SeriesCollection
{
get { return _series; }
set
{
_series = value;
RaisePropertyChanged("SeriesCollection");
}
}
public SeriesTrackerViewModel()
{
NewSeries = new DelegateCommand(AddNewSeries);
DataTable table = DataAccessLayer.GetSeries();
if (table.Rows.Count > 0)
LoadSeries(table);
}
private void LoadSeries(DataTable table)
{
foreach (DataRow row in table.Rows)
{
int id = Int32.Parse(row["Id"].ToString());
string name = row["Name"].ToString();
int season = 0;
int episode = 0;
if (Int32.TryParse(row["Season"].ToString(), out season) &&
Int32.TryParse(row["Episode"].ToString(), out episode))
{
var series = new Series(id, name, season, episode);
SeriesCollection.Add(series);
}
}
}
public void AddNewSeries()
{
SeriesCollection.AddSeries();
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Series class:
using System;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace SeriesTracker.Functions
{
public class Series : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private DelegateCommand _save;
public DelegateCommand Save
{
get { return _save; }
set
{
_save = value;
RaisePropertyChanged("Save");
}
}
private DelegateCommand _delete;
public DelegateCommand Delete
{
get{return _delete;}
set
{
_delete = value;
RaisePropertyChanged("Delete");
}
}
public int Id { get; set; }
string _name;
public String Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
int _season;
public Int32 Season
{
get { return _season; }
set
{
_season = value;
RaisePropertyChanged("Season");
}
}
int _episode;
public Int32 Episode
{
get { return _episode; }
set
{
_episode = value;
RaisePropertyChanged("Episode");
}
}
string _information;
public String Information
{
get { return _information; }
set
{
_information = value;
RaisePropertyChanged("Information");
}
}
public Series(int id,string name,int season, int episode)
{
Id = id;
Name = name;
Season = season;
Episode = episode;
Save = new DelegateCommand(SaveItem);
Delete = new DelegateCommand(DeleteItem);
}
public void DeleteItem()
{
var selectedItem = this;
if (selectedItem.Id != -1)
{
DataAccessLayer.Delete(selectedItem.Id);
}
}
public void SaveItem()
{
var selectedItem = this;
if (selectedItem.Id == -1)
DataAccessLayer.AddEntry(selectedItem.Name,selectedItem.Season,selectedItem.Episode);
else
DataAccessLayer.Update(selectedItem.Id,
selectedItem.Name,selectedItem.Season,selectedItem.Episode);
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Upvotes: 2
Views: 8421
Reputation: 23
You may subscribe to PropertyChangedEventHandler
of each Series in ObservableCollection
, and then invoke RaisePropertyChanged("SeriesCollection")
when event fired
UPDATE: I mean something like that:
private void LoadSeries(DataTable table)
{
...
{
var series = new Series(id, name, season, episode);
series.PropertyChanged += { RaisePropertyChanged("SeriesCollection"); }
SeriesCollection.Add(series);
}
}
Upvotes: 1
Reputation: 1584
You should not keep the DeleteCommand in Series class, it should be on the view model.
And in view model you can easily update the ObservableCollection.
You need to use Generic delegate command of Type Series on ViewModel and on XAML you need to pass {Binding} on command Parameter.
View Model C#:-
DelegateCommand<Series> DeleteCommand { get; set; }
DeleteCommand = new RelayCommand<Series>(OnDelete);
// This method will gets execute on click the of Delete Button1
private void OnDelete(Series series)
{
}
XAML :- On Delete button change the binding and command parameter value
CommandParameter="{Binding }"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
Hope this will help you
Upvotes: 4