Search code examples
c#wpflistviewmvvmrelaycommand

How do I add item to a list when I select the item from a listview and click add button in the UI on WPF


I'm a newbie so excuse my question if it's too fade or if it's unclear. any way, In my UI (WPF), i have a ListView that i created containing an observable collection of Type Collection = new ObservableCollection<type> and i have two Buttons "Add" & "Delete" I want to do this:

1-Whenever i select an item from my ListView in the UI(just click on it) , and click the "Add" button, the item is stored in a List called Scenario (Scenario = new List<type>).

2- Whenever i click the "Delete" button the Scenario list becomes empty.

I've tried something out but it doesn't work like it should, i can only add one item to the list Scenario and then it is blocked (when debugging) in

public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); }

Can someone tell me why? and how to fix it? As for the "Delete" Button i didn't get to it yet because the other one doesn't work properly.

if you can propose a new solution or a solution for this problem i would be so thankful.

This is what i've done so far.

This is the code in the MainWindowModel :

private ObservableCollection<Type> _collection,_scenario;
public MainWindowModel()
{
        Collection = new ObservableCollection<type>();
        Scenario=new ObservableCollection<Type>();
        DeleteCommand = new RelayCommand(o => DeleteExecute());
        AddTypeCommand = new RelayCommand(o => AddTypeExecute());

}
private Type _isSelected;
public Type IsSelected;
{
        get { return _isSelected;  }
        set
        {
            if (_isSelected != value)
            {
                _isSelected = value;
                RaisePropertyChanged(nameof(IsSelected));

            }
        }
}
public ICommand DeleteCommand
{
        get;
        private set;
}
private RelayCommand _addTypeCommand;
public ICommand AddTypeCommand
{
        get
        {
            if (_addTypeCommand == null)
            {
                _addTypeCommand = new RelayCommand(o => AddTypeExecute());
            }
            return  _addTypeCommand;
        }
        set { }
}

private void DeleteExecute()
{
        Scenario.Clear(); // Would this Work ?
}


private bool CanExecuteAddTypeCommand()
{
        return true;
}

private void AddTypeExecute()
{
        if (IsSelected != null)
        {

            Scenario.Add(IsSelected);

        }

}
public ObservableCollection<Type> collection
{
        get { return _collection; }
        set { SetPropertyAndFireEvent(ref _collection, value); }
}
public ObservableCollection<Type> Scenario
{
        get { return _scenario; }
        set { SetPropertyAndFireEvent(ref _scenario, value); }
}

as for the MainWindowModel

<Window.DataContext>
    <viewModels:MainWindowModel />
</Window.DataContext>

<Grid>
  <ListView Grid.Row="2" 
                  Grid.Column="0"
                  ItemsSource="{Binding Collection}"
                  SelectedItem="{Binding IsSelected}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
  </ListView>

  <Button Command="{Binding AddTypeCommand}" 
                Width="100" 
                Height="100" 
                Content="Add" 
                Grid.Row="0" 
                Grid.Column="2"/>

  <Button Command="{Binding DeleteCommand}" 
                Content="Delete" 
                Width="100" 
                Height="100" 
                Grid.Row="2"
                Grid.Column="2" />
</Grid>

As for the RelayCommand.cs

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;
    //Notifies the Button bounded to the ICommand that the value returned by CanExecute has changed 
    public event EventHandler CanExecuteChanged
    {
        //raised whenever the commandmanager thinks that something has changed that will affect the ability of commands to execute
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {

        return _canExecute == null || _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

Solution

  • Try passing selectedItem as parameter for command,you dont pass anything and try to add... name your ListView:

    <ListView x:Name="listView"
    

    and pass selectedItem as commandParameter

        <Button Command="{Binding AddTypeCommand}"
                CommandParameter="{Binding ElementName=listView, Path=SelectedItem}"
                Width="100"
                Height="100"
                Content="Add"
                Grid.Row="0"
                Grid.Column="2" />
    

    and then do your logic for adding, now you have parameter to add to your list.

    EDIT: Here is some code that works, as i have understand that u need something like this.

    ViewModel _> where all collection and command are created:

      public class TestVM : INotifyPropertyChanged
    {
        public TestVM()
        {
            ListOne = new ObservableCollection<string>()
            {
            "str1","str2","str3"
            };
    
            // command
            AddTypeCommand = new RelayCommand(OnAddExecute);
            DeleteTypeCommand = new RelayCommand(OnDeleteExecuted);
        }
    
        private void OnDeleteExecuted()
        {
            ListTwo.Clear();
        }
    
        private void OnAddExecute()
        {
            if (SelectedItem != null)
            {
                ListTwo.Add(SelectedItem);
            }
        }
    
        private string _selectedItem;
        public string SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    _selectedItem = value;
                    OnPropertyChanged();
                }
            }
        }
    
        private ObservableCollection<string> _listOne;
        public ObservableCollection<string> ListOne
        {
            get
            {
                return _listOne;
            }
            set
            {
                if (_listOne != value)
                {
                    _listOne = value;
                    OnPropertyChanged();
                }
            }
        }
    
        public ObservableCollection<string> ListTwo { get; set; } = new ObservableCollection<string>();
    
        public RelayCommand AddTypeCommand { get; private set; }
        public RelayCommand DeleteTypeCommand { get; private set; }
    
    
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        public virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    
    }
    

    RellayCommand how i implement it:

    public class RelayCommand : ICommand
        {
            private Action _executeMethod;
            private Func<bool> _canExecuteMethod;
    
            #region RelayCommand ctor
    
            public RelayCommand(Action executeMethod)
            {
                _executeMethod = executeMethod;
            }
    
            public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod)
            {
                _executeMethod = executeMethod;
                _canExecuteMethod = canExecuteMethod;
            }
    
            #endregion
    
            public void RaiseCanExecuteChanged()
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
    
    
            #region ICommand Members
    
            bool ICommand.CanExecute(object parameter)
            {
                if (_canExecuteMethod != null)
                    return _canExecuteMethod();
                if (_executeMethod != null)
                    return true;
                return false;
            }
    
            void ICommand.Execute(object parameter)
            {
                if (_executeMethod != null)
                    _executeMethod();
            }
    
            public event EventHandler CanExecuteChanged = delegate { };
    
            #endregion
        }
    
        //--------------------------------------------------------------------------------------------
    
        public class RelayCommand<T> : ICommand
        {
            private Action<T> _executeMethod;
            private Func<T, bool> _canExecuteMethod;
    
            #region RelayCommand ctor
    
            public RelayCommand(Action<T> executeMethod)
            {
                _executeMethod = executeMethod;
            }
    
            public RelayCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
            {
                _executeMethod = executeMethod;
                _canExecuteMethod = canExecuteMethod;
            }
    
            #endregion
    
            public void RaiseCanExecuteChanged()
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
    
    
            #region ICommand Members
    
            bool ICommand.CanExecute(object parameter)
            {
                var Tparam = (T)parameter;
                if (_canExecuteMethod != null)
                    return _canExecuteMethod(Tparam);
                if (_executeMethod != null)
                    return true;
                return false;
            }
    
            void ICommand.Execute(object parameter)
            {
                if (_executeMethod != null)
                    _executeMethod((T)parameter);
            }
    
            public event EventHandler CanExecuteChanged = delegate { };
    
            #endregion
        }
    

    And MainWindow.xaml just to show purpose. Selecting on one item in 1rst list and pressing button Add will add it to second ListView. DeleteButton will clear second list.

    <Window x:Class="WpfApp5.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp5"
            mc:Ignorable="d"
            Title="MainWindow"
            Height="350"
            Width="525">
        <Window.DataContext>
            <local:TestVM />
        </Window.DataContext>
        <Grid>
            <ListView x:Name="listViewOne"
                      ItemsSource="{Binding ListOne}"
                      SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
                      Width="100"
                      Height="200"
                      Margin="17,17,400,105" />
            <ListView x:Name="listViewTwo"
                      ItemsSource="{Binding ListTwo}"
                      Width="100"
                      Height="200"
                      Margin="339,17,78,105" />
            <Button Command="{Binding AddTypeCommand}"
                    Content="Add"
                    Grid.Row="0"
                    Margin="208,111,198,178" />
            <Button Command="{Binding DeleteTypeCommand}"
                    Content="Delete"
                    Grid.Row="0"
                    Margin="208,157,198,132" />
        </Grid>
    </Window>