-1

I have ComboBox with "ProjectList":

MainWindow.xaml

<ComboBox ItemsSource="{Binding Path=ProjectList}" IsSynchronizedWithCurrentItem="True" />

Elements are adding inside below method and working ok:

MainViewModel.cs

[AddINotifyPropertyChangedInterface]
public class MainViewModel{

 public ObservableCollection<string> ProjectList { get; internal set; } 
  = new ObservableCollection<string>(); 

  public async Task GetProjects(){
  ...
   foreach (AItem item in....)
   {
     ProjectList.Add(item.name)
   }
 }    
}

Note - I have installed "PropertyChanged.Fody".

Now I have added second ComboBox "TaskList" to xaml:

<ComboBox ItemsSource="{Binding Path=TaskList}" IsSynchronizedWithCurrentItem="True" />

List here should be created based on selected item into "ProjectList". Method is mostly the same, only has a parameter:

public ObservableCollection<string> TaskList { get; internal set; } 
 = new ObservableCollection<string>();

public async Task GetTask(string projectId = ""){
      ...
       foreach (AItem item in....)
       {
         TaskList.Add(item.name2)
       }
 }   

Now I want to addopt this to my MVVM.

Problem is: when and how to run GetTask()? Instead of "internal set" for ObservableCollection TaskList should be implemented "onpropertychanged"?

4est
  • 3,010
  • 6
  • 41
  • 63
  • 1
    Could you clarify your question? I'm not sure what you mean by _"Instead of "internal set" should be implemented "onpropertychanged"?"_ – default Aug 24 '18 at 07:51
  • I think you should look into a Master-Detail-View and consider changing your Project string to an object, that owns the TaskList which you can then bind to, instead of having everything in one ViewModel. – default Aug 24 '18 at 07:53
  • oh, you mean if you should implement a setter for your ObservableCollection (and thus INotifyPropertyChanged)? Then no, IMO don't do that. Call `.Clear()` and add items again. – default Aug 24 '18 at 08:01
  • @4est: What does PropertyChanged.Fody has to do with this? The ObservableCollection raises events to the UI when items are added and removed. This has nothing to with INotifyPropertyChanged. What are you trying to accomplish? – mm8 Aug 24 '18 at 09:53
  • @mm8 -> when you select Project the next cb should load (run) taskList – 4est Aug 24 '18 at 10:34
  • See my answer then. You need to call the method when the selection changes. – mm8 Aug 24 '18 at 10:39

3 Answers3

1

when you select Project the next cb should load (run) taskList

Then you should either bind the SelectedItem property of the ComboBox to a string source property and call the GetTask method in the setter of this one, e.g.:

    private string _selectedProject;
    public string SelectedProject
    {
        get { return _selectedProject; }
        set
        {
            _selectedProject = value;
            GetTask(_selectedProject);
        }
    }

...or invoke a command when the selection changes: Either from the setter:

set
{
    _selectedProject = value;
    YourCommand.Execute(null);
}

...or from the XAML markup using an interaction trigger.

Properties should not not really be kicking off asynchronous background operations in their setters. Please refer to my answer here for more information about this:

Is wrong to invoke an async method from property setter in WPF view model?

mm8
  • 163,881
  • 10
  • 57
  • 88
  • -> do I need to add SelectionChanged to CB into xaml? – 4est Aug 24 '18 at 10:45
  • No. Just bind to the source property: `` – mm8 Aug 24 '18 at 11:31
  • I got inf to "consider insert await"....when I put "await GetTask(_selectedProject)" then I got that await can be only used within an async method – 4est Aug 24 '18 at 12:57
  • That's why you shouldn't kick off asynchronous background operations in their setters. Did you read the links I supplied? – mm8 Aug 24 '18 at 12:58
  • ok - I have changed, but I'm getting all TaskList, not just for selected "Project"....I think that into wrong position I'm running GetTask – 4est Aug 24 '18 at 13:26
  • How is this related to your question? If you're getting "all TaskList" there is something wrong with your implementation of the method. – mm8 Aug 24 '18 at 13:36
  • hi, I had to write one more method to get ID and pass the id to TaskList method and working great, thank you for help @mm8 and others! – 4est Sep 03 '18 at 12:47
0

You need an event that's fired when the selected item of the ProjectList Combo box changes.

If you were using the code behind, you can just set the SelectionChanged property to point to a function. However it appears that you're using MVVM, so you need to add an interaction trigger to the combobox, a command for the trigger to call and a method for the command to call.

Add this namespace to the window:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

Change your combobox to include the trigger and to expose the SelectedItem

           <ComboBox ItemsSource="{Binding Path=ProjectList}" 
                     IsSynchronizedWithCurrentItem="True"
                     SelectedItem="{Binding SelectedProject}" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction Command="{Binding ReloadTasksCommand}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>

Then, in your ViewModel, add the ReloadTasksCommand command. You need to define the command, and the method that it calls.

private ICommand reloadTasks;
public ICommand ReloadTasksCommand => this.reloadTasks?? (this.reloadTasks= new RelayCommand(this.ReloadTasks));

public string SelectedProject{ get; set; }

private void ReloadTasks()
{
    GetTasks(this.SelectedProject);
}

I've also added a property for the SelectedProject, bound to the SelectedItem of the Project combobox.

RelayCommand is in the GalaSoft.MvvmLight.CommandWpf library. There are others, that's just what I use.

Robin Bennett
  • 3,192
  • 1
  • 8
  • 18
0

Change combobox like this:

       <ComboBox ItemsSource="{Binding Path=ProjectList}" 
                 IsSynchronizedWithCurrentItem="True"
                 SelectedItem="{Binding SelectedProject}" >                
       </ComboBox>

ViewModel:

private string _selectedObject;
public string SelectedObject
{
    get { return _selectedObject; }
    set
    {
        _selectedObject = value;
        //OnPropertyChanged(); -- INotifyPropertyChanged no need if Fody
        ReloadTasks();
    }
}

private void ReloadTasks()
{
    GetTasks(SelectedProject);
}
lokij
  • 29
  • 1
  • 2