Binding Button command which inside ListView Item WPF MVVM - c#

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.

Related

How to SelectItem of ListView having GridView

I want to select ListViewItem on Edit Button click of button, present in ListView inside GridView. Using MVVM Pattern.
Use case: Edit option in last column in GridViewColumn, on clicking edit button, I want to hide TextBlock and show TextBox, but to do this, I want to first selectItem of ListView on Edit Button's click
In below code,
I'm having ObservableCollection List,
User.cs is as below
private string _username;
private string _password;
private int _age;
private string _city;
public string Username { get => _username; set => _username = value; }
public string Password { get => _password; set => _password = value; }
public int Age { get => _age; set => _age = value; }
public string City { get => _city; set => _city = value; }
private bool _isEdit;
public bool IsEdit
{
get { return _isEdit; }
set
{
_isEdit = value;
OnPropertyChanged(nameof(IsEdit));
}
}
public User()
{
_username = String.Empty;
_password = String.Empty;
_city = String.Empty;
_isEdit = true;
}
public User(string username, string password, int age, string city)
{
this._username = username;
this._password = password;
this._age = age;
this._city = city;
_isEdit = true;
}
View File is as below
<ListView ItemsSource="{Binding List}"
Grid.Row="1"
SelectionMode="Single"
SelectedItem="{Binding SelectedUser}"
x:Uid="Table">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Center" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="IsSelected"
Value="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumnHeader Style="{StaticResource HeaderStyle}">
<ContentControl ContentTemplate="{StaticResource Header}"
Content="Username" />
</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Username}" />
<TextBox Text="{Binding Username}"
Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Style="{StaticResource HeaderStyle}">Age</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Age}" />
<TextBox Text="{Binding Age}"
Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Style="{StaticResource HeaderStyle}">City</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding City}" />
<TextBox Text="{Binding City}"
Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumnHeader Style="{StaticResource HeaderStyle}">Modify</GridViewColumnHeader>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Edit"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=DataContext.Edit}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Path=ListViewItems}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
To select an item from code you need to set the Property that is bound to "SelectedItem" and then call a NotifyChange.
In your case it would be inside the Button Click-Event:
SelectedUser=yourItem;
NotifyChange(nameof(SelectedUser))

How to delete row in listview MVVM?

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);
//...
}
}

Add image in wpf listview with c#

I am a new user to c# and WPF and I have a problem to populate a ListView with text and image.
This is my wpf code:
<Grid>
<ListView Name="MyList" Margin="0,0,328.4,-0.2" >
<ListView.View>
<GridView>
<GridViewColumn Header="Rete" DisplayMemberBinding="{Binding Rete}"/>
<GridViewColumn Header="Immagine" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Immagine}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
<Image Height="100" Width="100"/>
</ListView>
<Button Content="Button" HorizontalAlignment="Left" Margin="324,83,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
and this is my c# code:
while (r.Read())
{
MyList.Items.Add(new { Rete = r.GetString(0), Immagine = r.GetString(1) });
}
thanks to all i have solved!!! i changed the image path in the databse the code was correct!! :)
This is my xaml code.
<Grid>
<ListView x:Name="ListView1" VirtualizingStackPanel.IsVirtualizing="True" Height="200" 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="100" Height="50" Source="{Binding GridViewColumnName_ImageSource}" />
<Label Content="{Binding GridViewColumnName_LabelContent}" Width="50" Height="100" />
<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>
</ListView>
</Grid>
This is my c# part..
public ObservableCollection<ListViewItemsData> ListViewItemsCollections { get { return _ListViewItemsCollections; } }
ObservableCollection<ListViewItemsData> _ListViewItemsCollections = new ObservableCollection<ListViewItemsData>();
public MainWindow()
{
InitializeComponent();
ListViewItemsCollections.Add(new ListViewItemsData()
{
GridViewColumnName_ImageSource = #"D:\rd\C Sharp\general\StackOverFlowAnswers\WPF\MSD.JPG",
GridViewColumnName_LabelContent = "shanmugharaj"
});
ListView1.ItemsSource = 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; }
}
}
I tested with these its working fine..
If my understanding id right this is you need..

List Under ListView Item

I have listview that binding with observable Collection, this listview show the invoice items, any item in invoice maybe has a sub detail (Options), (for example item color),
what i want to ask about is: how to make list view show the item options as list under the main item in listview, i hope my question is clear .. for more clarity look at the image :
What i want is in a yellow color, how to make listview look like the image ?
here's my invoice listview code :
<ListView x:Name="temsReceipt" ItemsSource="{Binding ocItemsReceipt}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="40" Width="50"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Name" Width="230" DisplayMemberBinding="{Binding ItemName}"/>
<GridViewColumn Header="Item Price" Width="100" DisplayMemberBinding="{Binding ItemPrice}"/>
</GridView>
</ListView.View>
The same think if i used the datagrid
Let's say that you have following classes:
class InvoiceItem
{
public string ItemName { get; set; }
public List<InvoiceOption> Options { get; set; }
}
class InvoiceOption
{
public string OptionName { get; set; }
}
ListView solution:
<ListView x:Name="temsReceipt" ItemsSource="{Binding}">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="40" Width="50"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Name" Width="230" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding ItemName}" VerticalAlignment="Center"
FontWeight="Bold" FontSize="18"/>
<ListBox ItemsSource="{Binding Options}" Grid.Row="1" Background="Yellow"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OptionName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Price" Width="100" DisplayMemberBinding="{Binding ItemPrice}"/>
</GridView>
</ListView.View>
</ListView>
If you want to use DataGrid you can use RowDetailsTemplate:
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding ItemName}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Margin="2" Background="Yellow">
<TextBlock Text="Options:" />
<ListBox ItemsSource="{Binding Options}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OptionName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Sample data:
...
public MainWindow()
{
InitializeComponent();
List<InvoiceItem> _source = new List<InvoiceItem>
{
new InvoiceItem
{
ItemName = "Item1",
Options = new List<InvoiceOption>
{
new InvoiceOption { OptionName = "Option1" },
new InvoiceOption { OptionName = "Option2" }
}
},
new InvoiceItem
{
ItemName = "Item2",
Options = new List<InvoiceOption>
{
new InvoiceOption { OptionName = "Option3" },
new InvoiceOption { OptionName = "Option4" }
}
}
};
this.DataContext = _source;
}
...
ListView result:

Binding ListView

I have a ListView with the following code:
<ListView Name="ListView1">
<ListView.View>
<GridView>
<GridViewColumn Header="File" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="28" Height="28" Source="{Binding Icon}" Name="img"/>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" Text="{Binding File}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Type" Width="70" DisplayMemberBinding="{Binding Type}"/>
<GridViewColumn Header="Password" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Width="145" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Can someone tell me how can I add items in it during run time and set all the bindings (Icon,File,Type)?
You create a class like:
class MyData
{
public string File { get; set; }
public string Icon { get; set; } // a path to an Icon
...
}
and then you use (in for example Window_Loaded) an
ObservableCollection<MyData> data = new ObservableCollection<MyData>();
listView1.Items = data;
data.Add(new MyData { File="text", ... });

Categories

Resources