How to delete row in listview MVVM? - c#

I have 1 list. Each row of the list will have a delete button. I want to delete that line when I click that button and must use mvvm.
<ListView x:Name="ListViewRoutePlan" SelectedIndex="0" ItemsSource="{Binding RoutePlanResource}" Style="{StaticResource MaterialDesignListView}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}},Converter={StaticResource IndexConverter}}" Header="STT" />
<GridViewColumn DisplayMemberBinding="{Binding Prioritize}" Header="Prioritize" />
<GridViewColumn DisplayMemberBinding="{Binding PlanStatus}" Header="Plan Status" />
<GridViewColumn DisplayMemberBinding="{Binding Note}" Header="Note" />
<GridViewColumn Header="Delete" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding ElementName=ListViewRoutePlan,Path=DataContext.RemoveSubjectCommand}" CommandParameter="{Binding ElementName=ListViewRoutePlan}" Background="{x:Null}" BorderBrush="{x:Null}" Margin="0,-5,0,0" HorizontalAlignment="Left">
<materialDesign:PackIcon Kind="Delete" Margin="-5,0,0,0" Foreground="Black" Width="20" Height="20" />
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
view model
I have run it here but I do not know how to write processing code to delete
public class viewmodel : BaseViewModel
{
public ICommand RemoveSubjectCommand { get; set; }
public viewmodel()
{
RemoveSubjectCommand = new RelayCommand<ListView>((p) => { return true; }, (OnEdit));
}
private void OnEdit(ListView lsv)
{
}
}

The button command parameter should be the current item bound to the cell
CommandParameter="{Binding}"
And the command should be updated accordingly to remove the selected item from the collection
public class viewmodel : BaseViewModel {
public viewmodel() {
RemoveSubjectCommand = new RelayCommand<MyItemModel>((p) => { return true; }, (OnRemoveSubject));
//assuming RoutePlanResource initialized and populated
}
public ObservableCollection<MyItemModel> RoutePlanResource {
//assuming boilerplate getter and setter with notification
}
public ICommand RemoveSubjectCommand { get; set; }
private void OnRemoveSubject(MyItemModel item) {
RoutePlanResource.Remove(item);
//...
}
}

Related

How to get a list of selected items from a listview with checkboxes? (Without code behind)

Sorry if the question is unclear or the answer obvious, I have to work on this project for school without having had a deep dive in c# and WPF.
I built a list view with checkboxes following this
I would like to simply get the list of all items (category) with a thicked checkbox when I click the button "Filter categories".
I found kind of similar questions with answers involving using code behind which I can't do.
<ListView x:Name="ListViewCategories" ItemsSource="{Binding CourseCategories}" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Title}" Header="Category"/>
<GridViewColumn Header="Display" >
<GridViewColumn.CellTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsSelected,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
<Button Content="Filter Categories" Command="{Binding FilterCategory}" CommandParameter="???" />
Should I pass this to the ViewModel with the button CommandParameter? If yes, how?
If no, how can I get the list of selected items in my ViewModel?
The essential of the ViewModel:
namespace Project.ViewModel {
public class QuestionsViewModel : ViewModelCommon {
private Course course;
public Course Course { get => course; set => SetProperty(ref course, value, OnRefreshData); }
private ObservableCollection<Category> courseCategories;
public ObservableCollection<Category> CourseCategories {
get => courseCategories;
set => SetProperty(ref courseCategories, value);
}
public ICommand FilterCategory { get; set; }
public QuestionsViewModel() : base() {
FilterCategory = new RelayCommand<List<Category>>(categories => {
foreach (var c in categories) {
Console.WriteLine(c.Title);
}
});
}
}
}
Should I add a bool property display in the "category" model and bind it to the checkbox?
If yes, I still don't know how to get a list of all thicked items.
Should I add a bool property display in the "category" model and bind it to the checkbox?
Yes.
If yes, I still don't know how to get a list of all thicked items.
Just filter them out from the courseCategories collection, for example using LINQ:
var checkedItems = courseCategories.Where(x => x.YourBoolProperty).ToArray():
For those who want to achieve the same thing.
I have added a bool property to the model ("Display").
<ListView x:Name="ListViewCategories" ItemsSource="{Binding CourseCategories}" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Title}" Header="Category" />
<GridViewColumn Header="Display" >
<GridViewColumn.CellTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Display}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
<Button Content="Filter Categories" {Binding FilterCategory}" Style="{StaticResource DarkBlueButton}" />
Bound the checkbox with display in the ViewModel
public bool? Display {
get { return Display; }
set { Display = value; }
}
public ICommand FilterCategory { get; set; }
public QuestionsViewModel() : base() {
FilterCategory = new RelayCommand(() => {
var checkedItems = courseCategories.Where(x => x.Display).ToArray();
foreach (var c in checkedItems) {
Console.WriteLine(c.Title);
}
});
}

Binding Button command which inside ListView Item WPF MVVM

I have a ListView that outputs the content. total of 4 columns: Chapter number, title, edit button, delete button
When you click on the button, you need to get the element where it is located (for example, the Chapter number or Chapter name). I tried to do binding via the ListView name and via FindAncestor, but nothing happened.
Please help solve the problem or point out errors
XAML:
<ListView Name="TableOfContents"
ItemsSource="{Binding Path=ContentList}"
Background="{x:Null}" Width="600"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True"
BorderBrush="{x:Null}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{Binding Command}"
CommandParameter="{Binding ElementName=TableOfContents, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View>
<GridView>
<GridViewColumn Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ThemeID}" TextWrapping="Wrap"
Foreground="Black" FontSize="30"
TextAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="460">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ThemeName}" TextWrapping="Wrap"
Foreground="Black" FontSize="20"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="40">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="🖊" ToolTip="Редактировать"
Foreground="Black" FontSize="18"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ItemsControl}},
Path=TableOfContentsPageViewModel.EditTheme}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="40">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="❌" ToolTip="Удалить"
Foreground="Black" FontSize="18"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ItemsControl}},
Path=TableOfContentsPageViewModel.DeleteTheme}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
ViewModel:
class TableOfContentsPageViewModel:BaseViewModel, IPageViewModel
{
public string SearchedChapter { get; set; }
public Visibility CanEdit { get; set; } = Visibility.Hidden;
public Theme SelectedTheme { get; set; }
public ObservableCollection<Theme> ContentList { get; set; }
public TableOfContentsPageViewModel()
{
ContentList = new ObservableCollection<Theme>(TrainSQL_Commands.GetAllThemes());
CanEdit = CurrentUser.Role == "Administrator" ? Visibility.Visible : Visibility.Hidden;
}
private ICommand _editTheme;
public ICommand EditTheme
{
get
{
return _editTheme ?? (_editTheme = new RelayCommand(x =>
{
MessageBox.Show("Edit theory");
}));
}
}
private ICommand _deleteTheory;
public ICommand DeleteTheme
{
get
{
return _deleteTheory ?? (_deleteTheory = new RelayCommand(x =>
{
MessageBox.Show("Delete theory");
}));
}
}
}
Image: https://i.stack.imgur.com/cpROA.png
Welcome to SO!
RelativeSource binds to the control itself, not via the DataContext (which make sense when you think about it). You're currently binding to the Path TableOfContentsPageViewModel.DeleteTheme, you need to change that to DataContext.TableOfContentsPageViewModel.DeleteTheme.

C# ListView Relay Command Binding

Can someone help me with the list view with grid. I want when you click on an element that a function is called and I get the current item. I already have the following XAML code:
<ListView Name="lstView" ItemsSource="{Binding Path=SimResults}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedItemCommand}" CommandParameter="{Binding SelectedItem, ElementName=lstView}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="FileUniqueID" Width="Auto" DisplayMemberBinding="{Binding Path=FileUniqueID}" />
<GridViewColumn Header="XML" Width="Auto" DisplayMemberBinding="{Binding Path=XML}" />
<GridViewColumn Header="Request" Width="Auto" HeaderStringFormat="" DisplayMemberBinding="{Binding Path=RequestShort}" />
<GridViewColumn Header="RequestDate" Width="Auto" DisplayMemberBinding="{Binding Path=RequestDate}" />
<GridViewColumn Header="Response" Width="Auto" DisplayMemberBinding="{Binding Path=ResponseShort}" />
<GridViewColumn Header="ResponseDate" Width="Auto" DisplayMemberBinding="{Binding Path=ResponseDate}" />
<GridViewColumn Header="ResendCounter" Width="Auto" DisplayMemberBinding="{Binding Path=ResendCounter}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
In the cs file I have the following functions:
private Item selectedItem;
private RelayCommand selectedItemCommand;
this.selectedItemCommand = new RelayCommand(this.SelectedItems);
public Item SelectedItem
{
get { return selectedItem; }
set { selectedItem = value; OnPropertyChanged("SelectedTrends"); }
}
public RelayCommand SelectedItemCommand
{
get
{
return this.selectedItemCommand;
}
}
private void SelectedItems(object obj)
{
this.requestXml = this.selectedItem.DisplayName;
}
When I select an element the selectedItems and I can get the item.
Hi I tested the code above and it worked fine. But I have problem. I have different tabs, when I click a different tab with the left click it always runs the SelectionChanged event and I get a Null reference exception.
One solution is to create a property for the "SelectedItem" from the listView.
So, in your VM:
private YourType _selectedResult;
public YourType SelectedResult
{
get { return _selectedResult; }
set { _selectedResult= value; OnPropertyChanged("SelectedResult"); }
}
And bind this proprety on your ListView:
<ListView Name="lstView" ItemsSource="{Binding Path=SimResults}" SelectedItem="{Binding SelectedResult}">
Just make sure you initialize selectedItemCommand before InitializeComponent() in the ctor, eg:
public MainWindow()
{
this.selectedItemCommand = new RelayCommand(this.SelectedItems);
InitializeComponent();
}

Unable to Bind ObservableCollection from MVVM to ListView in WPF

I am trying to bind the List View to Observable Collection of a class and for some reason, the DisplayMemberBinding attribute of GridViewColumn is not binding to the content of collection.
If I use ListView.ItemTemplate, everything works fine. But I need the data in the form of a grid, so I am using GridView inside ListView.View.
First Image, Image 1 is the AssessmentSummaryList content in debug mode.
Second Image, Image 2 is the final output shown on the screen. The content from the list is not binding to the GridViewColumn.
These are the two view models I am using:
public class AssessmentSummaryViewModel : BaseViewModel
{
public string Question { get; set; }
public string Title { get; set; }
public string SelectedOption { get; set; }
public int Id { get; set; }
}
public class AssessmentViewModel : BaseViewModel
{
private ObservableCollection<AssessmentSummaryViewModel> assessmentSummaryList;
public ObservableCollection<AssessmentSummaryViewModel> AssessmentSummaryList
{
get { return assessmentSummaryList; }
set
{
assessmentSummaryList = value;
NotifyPropertyChanged("AssessmentSummaryList");
}
}
public void SetNextAssessment()
{
AssessmentSummaryList= Service.GetAssessmentSummary(ApplicationModel.SelectedModule.Id,
ApplicationModel.SelectedUtility.Id); //the service returns ObservableCollection<AssessmentSummaryViewModel> data
var EndScreen = new AssessmentSummaryView(); //Setting the last screen to AssessmentSumamryView, this will be called dynamically from other UserControl Xaml Page
}
}
AssessmentSummaryView Xaml Code is as follows:
<ListView x:Name="lstvSummary1" Grid.Row="2" ItemsSource="{Binding Path=DataContext.AssessmentSummaryList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn DisplayMemberBinding="{Binding Path=Title}" Width="200">
<GridViewColumnHeader Content="Design Element" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=Question}" Width="400">
<GridViewColumnHeader Content="Question" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=SelectedOption}" Width="300">
<GridViewColumnHeader Content="Response" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
AssessmentSummaryView Code-behind is as follows:
public partial class AssessmentSummaryView : UserControl
{
public AssessmentSummaryView()
{
InitializeComponent();
}
}
Try something like:
<ListView ItemsSource="{Binding Path=DataContext.AssessmentSummaryList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Design Element" Width="200" DisplayMemberBinding="{Binding Path=Title}"/>
<GridViewColumn Header="Question" Width="400" DisplayMemberBinding="{Binding Path=Question}"/>
<GridViewColumn Header="Response" Width="300" DisplayMemberBinding="{Binding Path=SelectedOption}"/>
</GridView.Columns>
</GridView>
</ListView.View>

Creating the ListView in WPF?

Hi guys and happy new year(2010).
I'm a kind of novice in WPF's ListView.
I'm gonna create the following ListView in WPF via XAML and C# :
http://xs.to/image-A835_4B3EF7EE.jpg
Could you please guide me , how I can do it ?
Thanks.
I've done it with the below XAML code :
<ListView x:Name="ListView1" Background="#FFEEF3FA" SelectionChanged="ListView1_SelectionChanged" VirtualizingStackPanel.IsVirtualizing="True" local:ListViewSorter.IsListviewSortable="True" MouseDoubleClick="ListView1_MouseDoubleClick" ItemsSource="{Binding ListViewItemsCollections}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn x:Name="GridViewColumnName" Header="Name" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image x:Name="Image_GridViewColumnName" Width="16" Height="16" Source="{Binding GridViewColumnName_ImageSource}" />
<Label Content="{Binding GridViewColumnName_LabelContent}" />
<Label Content="{Binding GridViewColumnName_ID}" Visibility="Hidden" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="GridViewColumnTags" Header="Tags" Width="100" DisplayMemberBinding="{Binding GridViewColumnTags}" />
<GridViewColumn x:Name="GridViewColumnLocation" Header="Location" Width="238" DisplayMemberBinding="{Binding GridViewColumnLocation}" />
</GridView>
</ListView.View>
and following C# code :
public partial class MainWindow : Window
{
ObservableCollection<ListViewItemsData> _ListViewItemsCollections = new ObservableCollection<ListViewItemsData>();
public ObservableCollection<ListViewItemsData> ListViewItemsCollections { get { return _ListViewItemsCollections; } }
}
public class ListViewItemsData
{
public string GridViewColumnName_ImageSource { get; set; }
public string GridViewColumnName_LabelContent { get; set; }
public string GridViewColumnName_ID { get; set; }
public string GridViewColumnTags { get; set; }
public string GridViewColumnLocation { get; set; }
}

Categories

Resources