Reputation: 1926
I'm currently learning how to implement Commands into C#/WPF projects. Suppose I have a class MyClass
with a simple command MyCommand
.
public class MyClass
{
private RelayCommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
_myCommand = new RelayCommand(_ => ExecuteMyCommand());
return _myCommand;
}
}
private void ExecuteMyCommand()
{
// Do work...
}
}
Now, suppose I created an ObservableCollection<MyClass>
in a view model, which is bound to a ListView. The ListView has a GridViewColumn with buttons bound to MyCommand. Everything works great.
public class MyViewModel
{
private ObservableCollection<MyClass> _myCollection;
public ObservableCollection<MyClass> MyCollection
{
get { return _myCollection; }
set
{
_myCollection = value;
RaisePropertyChanged("MyCollection");
}
}
public void Refresh()
{
// Do work to refresh MyCollection to it's "live" state
}
}
Now I need to call the Refresh() method on the view model after the one of the objects in MyCollection executes MyCommand, but I'm not sure how to approach this situation.
Things I have tried:
Things I have considered:
ObservableCollection<MyClass>
, adding a reference property like mentioned previously but referencing the ObservableCollection instead of the view model, which wouldn't feel as messy but still not really perfect in my eyes...What would be the best/correct way to approach this problem?
Upvotes: 1
Views: 72
Reputation: 41
You can also put a click event on the buttons (they bubble up to the view), and call the command from code-behind
Upvotes: 0
Reputation: 5935
Another way to turn this on is the following:
<MenuItem Content="Run MyCommand"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.RefreshCommand}"
CommandParameter="{Binding}"/>
Then, in your MyViewModel
public class MyViewModel
{
private ObservableCollection<MyClass> _myCollection;
public ObservableCollection<MyClass> MyCollection
{
get { return _myCollection; }
set
{
_myCollection = value;
RaisePropertyChanged("MyCollection");
}
}
//...
private ICommand _refreshCommand;
public ICommand RefreshCommand
{
get
{
if (_refreshCommand== null)
_refreshCommand= new RelayCommand<MyClass>(p => Refresh(p));
return _refreshCommand;
}
}
public void Refresh(MyClass parameter)
{
if (null == parameter)
return;
parameter.ExecuteMyCommand();
// Do work to refresh MyCollection to it's "live" state
}
}
Note: currently you do not need to have the MyCommand
on each MyClass
instance - you can pass it as a parameter to the parent view model.
I cannot say that there is the right way to accomplish your task. So I cannot say which one is better.
Upvotes: 1
Reputation: 1926
I managed to get this to work in (I think) a pretty nice way.
First of all, I changed Refresh() to a command. I then added a parameter to the MyCommand method. The method does its work, and then checks the parameter to see if it's a command, and then executes it.
private void ExecuteMyCommand(object param)
{
// Do work...
if (param != null && param is ICommand)
((ICommand)param).Execute(null);
}
Then in XAML for the View, I set the CommandParameter to the command I want it to run afterwards.
<MenuItem Content="Run MyCommand"
Command="{Binding UploadCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.RefreshCommand}"/>
If no CommandParameter is supplied in XAML, it passes null. Done...
Upvotes: 0