Где я могу разместить логику для моей ICommand?
Я недавно начал использовать шаблон MVVM в Silverlight, и я не уверен, правильно ли я его использую.
графический интерфейс пользователя
В настоящее время у меня есть MainView, который имеет комбобокс секторов фондового рынка. Когда пользователь выбирает сектор (например, ENERGY) и нажимает кнопку "Добавить", список акций для этого сектора отображается в списке. Рядом с каждой акцией в списке находится кнопка удаления, которая позволяет удалить отдельную акцию из списка.
Я реализовал следующие ViewModels. (Ниже приведено только указание кода)
public class MainViewModel
{
public SectorViewModel CurrentSector
{
get;
set;
}
public string SelectedSector
{
get;
set;
}
public void AddSectorClickedCommand()
{
CurrentSector = new SectorViewModel(SelectedSector);
}
}
public class SectorViewModel
{
public ObservableCollection<StockViewModel> Stocks = new ObservableCollection<StockViewModel>();
public SectorViewModel(string sector)
{
List<Stocks> stocklist = StockProvider.GetStocks(sector);
for each (var s in stocklist)
{
StockViewModel svm = new StockViewModel(s);
svm.Remove+= { //Remove svm from Stocks collection logic
Stocks.add(svm);
}
}
}
Мой вопрос в какой viewmodel лучше всего добавить реализацию кода для кнопки "Удалить" каждой строки в списке?? Кнопка Удалить должна удалить StockViewModel из коллекции SectorViewModel.Stocks.
В настоящее время я добавил метод RemoveClicked в StockViewModel(как показано выше). Этот код запускает событие обратно в SectorViewModel, а метод Remove Stock объекта SectorViewModel удаляет StockViewModel из коллекции Stock.
Есть ли лучший способ реализовать эту функцию удаления? Я новичок в MVVM и не уверен, что это лучший подход для разработки этой функциональности, поскольку SectorViewModel должен регистрироваться на события StockViewModel.
1 ответ
Лично мне не нравятся события, потому что вы должны отписаться от них, а также они могут быть использованы там, где это не подходит.
Я бы использовал параметр конструктора для обработки команды удаления, что-то вроде этого:
public class StockViewModel
{
public StockViewModel(Stock stock, Action<StockViewModel> removeCommandAction)
{
//...
this.RemoveCommand = new DelegateCommand(() => removeCommandAction(this));
}
}
public class SectorViewModel
{
public SectorViewModel()
{
//...
StockViewModel svm = new StockViewModel(s, this.RemoveStock);
Stocks.add(svm);
}
private void RemoveStock(StockViewModel stock)
{
//...
}
}
Другой подход заключается в использовании какого-либо шаблона EventAggregator, например, Messenger
класс из легкого инструментария MVVM. Но я думаю, что это излишнее решение для такой простой задачи:
public StockViewModel(Stock stock, IMessenger messenger)
{
//...
this.RemoveCommand = new DelegateCommand(() =>
messenger.Send(new NotificationMessage<StockViewModel>(this, RemoveItemNotification)));
}
public SectorViewModel(IMessenger messenger)
{
//...
messenger.Register<NotificationMessage<StockViewModel>>(this, msg =>
{
if (msg.Notification == StockViewModel.RemoveItemNotification)
{
this.RemoveStock(msg.Content);
}
}
}
Также я слышал, что Silverlight 5 поддерживает привязку к относительному источнику. Так что есть 3-й подход. Я не уверен, работает ли этот пример, но, по крайней мере, он должен:
<Button Content="Remove"
Command="{Binding DataContext.RemoveCommand RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}" />
public class SectorViewModel
{
public SectorViewModel()
{
this.RemoveCommand = new DelegateCommand(obj => this.RemoveStock((StockViewModel)obj));
}
public ICommand RemoveCommand { get; set; }
}
Последний пример, кстати, наиболее предпочтителен и используется в приложениях WPF, потому что WPF всегда имел привязку RelativeSource.