question

Sarah-3412 avatar image
0 Votes"
Sarah-3412 asked PeterFleischer-3316 answered

How to Iterate listview items using MVMV

Can someone help and show me how to iterate ListView items using MVVM?

In the Code Behind it is done as follows:

 for (int i = 0; i < NameOfListView.Items.Count; i++)
 {
 //code
 }

In MVVM unfortunately I don't know how to address the ListView.
The goal is to iterate over all items/rows and store the content in a list.

windows-wpf
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi Sarah,
bind collection to ItemsSource of ListView and iterate through collection or use attached property to catch reference to ListView.

0 Votes 0 ·
Sarah-3412 avatar image Sarah-3412 PeterFleischer-3316 ·

Hi @PeterFleischer-3316 , A collection is already bound to ItemSource. I change this collection (several items/rows at the same time) in the ListView. Now I want to save the new collection. Iterate through collection is not a solution, because the new changes are not in yet.

Attached property can be a solution but I don't understand how to use it to iterate ListView items. Do you have an example?

0 Votes 0 ·
HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered HuiLiu-MSFT commented

I'm not sure what kind of iteration effect you want. You could take a look at the example below. Any questions please let me know.
MainWindow.xaml:

  <StackPanel>
         <ListView x:Name="MColumnsListXaml" HorizontalAlignment="Left"  
                   Height="Auto" Margin="0,42,0,0" VerticalAlignment="Top"  
                   Width="Auto" ItemsSource="{Binding MColumnsList}">
             <ListView.View>
                 <GridView>
                     <GridViewColumn Header="First Name" Width="Auto" DisplayMemberBinding="{Binding MColumnName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
                     <GridViewColumn Header="Last Name" Width="Auto" DisplayMemberBinding="{Binding MColumnName2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
                 </GridView>
             </ListView.View>
         </ListView>
         <Button x:Name="btn" Content="load" Width="100" Height="40" Click="btn_Click" />
         <TextBlock x:Name="tb"  Width="100" Height="40"  />
         <DataGrid x:Name="dg"  />
     </StackPanel>

MainWindow.xaml.cs:

 using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.Runtime.CompilerServices;
 using System.Windows;
    
 namespace ListViewIterate
 {
   public partial class MainWindow : Window
   {
     public MainWindow()
     {
       InitializeComponent();
       DataContext =new ViewModel();
     }
     public ObservableCollection<MandatoryColumns> DGItems;
     public void test()
     {
        ObservableCollection<MandatoryColumns> items = (ObservableCollection<MandatoryColumns>)MColumnsListXaml.ItemsSource;
     
   foreach (var item in items)
   {
     DGItems = new ObservableCollection<MandatoryColumns>();
      
     item.MColumnName="item";
     DGItems.Add(item);
     tb.Text = item.ToString();

   }
   dg.ItemsSource = items;
     }
    
     private void btn_Click(object sender, RoutedEventArgs e)
     {
       test();
     }
   }
   public class ViewModel : INotifyPropertyChanged
   {
     private ObservableCollection<MandatoryColumns> mColumnsList;
     public ObservableCollection<MandatoryColumns> MColumnsList
     {
       get { return mColumnsList;}
       set { mColumnsList=value; OnPropertyChanged("MColumnsList");}
     }
     public ViewModel()
     {
        MColumnsList = new ObservableCollection<MandatoryColumns>();
       MColumnsList.Add(new MandatoryColumns() { MColumnName = "John", MColumnName2 = "Smith" });
       MColumnsList.Add(new MandatoryColumns() { MColumnName = "Jason", MColumnName2 = "Bell" });
       MColumnsList.Add(new MandatoryColumns() { MColumnName = "Jason1", MColumnName2 = "Bell2" });
         
     }
     public event PropertyChangedEventHandler PropertyChanged;
     protected void OnPropertyChanged([CallerMemberName] string name = null)
     {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
     }
   }
   public class MandatoryColumns
   {
     public string MColumnName { get; set; }
     public string MColumnName2 { get; set; }
    
     public override string ToString()
     {
       return (MColumnName + "--"+MColumnName2) .ToString();
     }
   }
 }

Update:
MainWindow.xaml:

 <Window.DataContext>
         <local:ViewModel/>
     </Window.DataContext>
     <StackPanel>
         <ListView  ItemsSource="{Binding View}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
             <ListView.View>
                 <GridView AllowsColumnReorder="False">
                     <GridViewColumn Header="CLM1">
                         <GridViewColumn.CellTemplate>
                             <DataTemplate>
                                 <TextBlock Text="{Binding Cont1, UpdateSourceTrigger=PropertyChanged}" 
                                            TextWrapping="Wrap"/>
                             </DataTemplate>
                         </GridViewColumn.CellTemplate>
                     </GridViewColumn>
    
                     <GridViewColumn Header="CLM2">
                         <GridViewColumn.CellTemplate>
                             <DataTemplate>
                                 <TextBox Text="{Binding Cont2, UpdateSourceTrigger=PropertyChanged}"
                                          TextWrapping="Wrap"
                                          Width="100"/>
                             </DataTemplate>
                         </GridViewColumn.CellTemplate>
                     </GridViewColumn>
    
                     <GridViewColumn Header="CLM3">
                         <GridViewColumn.CellTemplate>
                             <DataTemplate>
                                 <TextBox Text="{Binding Cont3, UpdateSourceTrigger=PropertyChanged}"
                                          TextWrapping="Wrap"
                                          Width="100"/>
                             </DataTemplate>
                         </GridViewColumn.CellTemplate>
                     </GridViewColumn>
                 </GridView>
             </ListView.View>
         </ListView>
         <Button Content="Add Item" Command="{Binding CmdSaveNew}" Width="150" Margin="5"/>
         <Button Content="Delete Item" Command="{Binding CmdDelete}" Width="150" Margin="5"/>
         <Button Content="Iterate"
                 Width="70"
                 Height="50"
                 Command="{Binding Cmd}"
                 CommandParameter="Iterate"/>
         <ListView   x:Name="output" ItemsSource="{Binding Output}"   >
             <ListView.ItemsPanel>
                 <ItemsPanelTemplate>
                     <StackPanel Orientation="Horizontal"></StackPanel>
                 </ItemsPanelTemplate>
             </ListView.ItemsPanel>
         </ListView>
     </StackPanel>

MainWindow.xaml.cs:

 public class ViewModel : INotifyPropertyChanged
   {
     private CollectionViewSource cvs = new CollectionViewSource();
     public ICollectionView View
     {
       get
       {
         cvs.Source = InitImput();
         return cvs.View;
       }
     }
     public ViewModel()
     {
       CmdSaveNew = new RelayCommand(SaveNew);
       CmdDelete = new RelayCommand(DeleteItem);
     }
      int id=5;
     public void SaveNew(object parameter)
     {
       if (!string.IsNullOrEmpty("x")) 
       {
         Model cat = new Model();
         cat.Cont1 = $"{id}"; 
         cat.Cont2 = ""; 
         cat.Cont3 = ""; 
           Input.Add(cat);
         MessageBox.Show("success");
         id+=1;
       }
       else
       {
         MessageBox.Show("error");
       }
     }
     public void DeleteItem(object parameter)
     {
       if (SelectedItem != null)
       {
         Input.Remove(SelectedItem);
       }
     }
     public ICommand Cmd { get => new RelayCommand(CmdExec); }
     public ICommand CmdSaveNew { get; set; }
     public ICommand CmdDelete { get; set; }
    
     private void CmdExec(object parameter)
     {
       switch (parameter.ToString())
       {
         case "Iterate":
    
           for (int i = 0; i < Input.Count; i++)
           {
             Output.Add(Input[i]);
           }
    
           MessageBox.Show("Items Added");
           break;
    
         default:
           break;
       }
     }
     private Model _selectedItem;
     public Model SelectedItem
     {
       get { return _selectedItem; }
       set
       {
         _selectedItem = value;
         OnPropertyChanged("SelectedItem");
       }
     }
     private ObservableCollection<Model> output = new ObservableCollection<Model>();
     public ObservableCollection<Model> Output { get { return output;}set{ output=value;OnPropertyChanged("Output");} } 
    
    
     public event PropertyChangedEventHandler PropertyChanged;
     protected void OnPropertyChanged([CallerMemberName] string name = null)
     {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
     }
    
     ObservableCollection<Model> Input = new ObservableCollection<Model>();
     public ObservableCollection<Model> InitImput()
     {
       Input.Add(new Model() { Cont1 = "1", Cont2 = "A", Cont3 = "a" });
       Input.Add(new Model() { Cont1 = "2", Cont2 = "B", Cont3 = "b" });
       Input.Add(new Model() { Cont1 = "3", Cont2 = "C", Cont3 = "c" });
       Input.Add(new Model() { Cont1 = "4", Cont2 = "D", Cont3 = "d" });
    
       return Input;
     }
    
   }
    
   public class Model
   {
     public string Cont1 { get; set; }
     public string Cont2 { get; set; }
     public string Cont3 { get; set; }
     public override string ToString()
     {
       return Cont1+ Cont2+ Cont3 .ToString();
     }
   }
    
   public class RelayCommand : ICommand
   {
     private readonly Predicate<object> _canExecute;
     private readonly Action<object> _action;
     public RelayCommand(Action<object> action) : this(action, null) { }
     public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
     public void Execute(object o) => _action(o);
     public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
     public event EventHandler CanExecuteChanged
     {
       add { CommandManager.RequerySuggested += value; }
       remove { CommandManager.RequerySuggested -= value; }
     }
   }

The result:
205319-88.gif


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



55.gif (65.6 KiB)
44.gif (95.1 KiB)
88.gif (444.2 KiB)
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @HuiLiu-MSFT , Thanks for the code but unfortunately it is not what I want to do. I use a DataTemplate with TextBox inListView. The ListView has Init values at the beginning. Via the TextBox the values can be changed. I want to save the new items/rows in List Output when I click the button.

In the attached file I have my code how I want to do that. Maybe you can help me to get the commented out code (case "Iterate") to work. In MVVM unfortunately I don't know how to address the ListView.
204986-lviterate.txt


0 Votes 0 ·
lviterate.txt (5.4 KiB)

Hi,@Sarah-3412. The ItemsSource of ListView is Input, is it possible to loop Input?

  <ListView x:Name="output" ItemsSource="{Binding Output}"/>
    
  private ObservableCollection<Model> output = new ObservableCollection<Model>();
     public ObservableCollection<Model> Output { get { return output;}set{ output=value;OnPropertyChanged("Output");} } 
    
  case "Iterate":
    
           for (int i = 0; i < Input.Count; i++)
           {
             Output.Add(Input[i]);
           }
    
           MessageBox.Show("Items Added");
           break;
  public class Model
   {
     public string Cont1 { get; set; }
     public string Cont2 { get; set; }
     public string Cont3 { get; set; }
     public override string ToString()
     {
       return Cont1+ Cont2+ Cont3 .ToString();
     }
   }

204965-55.gif



0 Votes 0 ·
55.gif (222.1 KiB)

Hi @HuiLiu-MSFT , No, it is not possible to loop Input. It is only an init list. The ListView can have more or less items as input list. How to communicate with the ListView in MVVM?

In Code Behind is made as follows:

 for (int i = 0; i < NameOfListView.Items.Count; i++)
 {
     Output.Add((Model)Items[i]);
 }


0 Votes 0 ·
Show more comments
PeterFleischer-3316 avatar image
0 Votes"
PeterFleischer-3316 answered

Hi Sarah,
the simplest way is to use Input for Add to Output because Input is binded to ListView and reflect all Items in LIstView:

 public ICommand Cmd { get => new RelayCommand(CmdExec); }
 private void CmdExec(object parameter)
 {
   switch (parameter.ToString())
   {
     case "Iterate":
       for (int i = 0; i < Input.Count; i++) Output.Add(Input[i]);
       MessageBox.Show("Items Added");
       break;
     default:
       break;
   }
 }
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.