Я пытался использовать функцию MVVMLight Event to Command, чтобы связать команды в моей ViewModel с событиями, такими как TextChanged в TextBox, например. Дело в том, что в UWP Event to Command автоматически предполагает, что параметр команды является аргументами события TextChanged. Я не хочу этого, я хочу отправить модель в качестве параметра команды, например:
<ListView ItemsSource="{Binding ListaAgendaReceita}" Background="DimGray" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Valor, Mode=TwoWay, Converter={StaticResource CVTStringTODecimal}, UpdateSourceTrigger=PropertyChanged}" Background="LightGray">
<interact:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="TextChanged">
<core:InvokeCommandAction Command="{Binding ElementName=usr_Receita, Path=DataContext.ModificacaoAgendaReceita}"
CommandParameter="{Binding}"/>
</core:EventTriggerBehavior>
</interact:Interaction.Behaviors>
</TextBox>
</DataTemplate>
</ListView.ItemTemplate>
<ListView/>
РЕДАКТИРОВАТЬ .: этот TextBox является частью DataTemplate внутри ListView. Я отредактировал блок кода, чтобы отразить это более четко. Я также привожу тот же пример, но для CalendarDatePicker, которому всегда не удается отправить модель в качестве параметра команды, вместо этого отправив аргументы событий.
<ListView ItemsSource="{Binding ListaAgendaReceita}" Background="DimGray" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<CalendarDatePicker BorderThickness="0,3,0,1" DateFormat="{}{day.integer}/{month.integer}/{year.full}"
Date="{Binding Data, Mode=TwoWay, Converter={StaticResource CVTDateTimeTODateTimeOffsetTwoWay}}"
BorderBrush="Green" Background="DarkGray">
<interact:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DateChanged">
<core:InvokeCommandAction Command="{Binding ElementName=usr_Receita, Path=DataContext.ModificacaoAgendaReceita}"
CommandParameter="{Binding}"/>
</core:EventTriggerBehavior>
</interact:Interaction.Behaviors>
</CalendarDatePicker>
</DataTemplate>
</ListView.ItemTemplate>
<ListView/>
CVTDateTimeTODateTimeOffsetTwoWay - это простой конвертер, который обрабатывает свойство DateProperty, конвертируя из DateTime в DateTimeOffset и наоборот.
public class CVTDateTimeTODateTimeOffsetTwoWay : IValueConverter
{
public object Convert(object value, Type TargetType, object parameter, string culture)
{
var Data = (DateTime)value;
DateTime date = new DateTime(Data.Year, Data.Month, Data.Day, Data.Hour, Data.Minute, 0);
return new DateTimeOffset(date);
}
public object ConvertBack(object value, Type TargetType, object parameter, string culture)
{
if (value != null)
{
DateTimeOffset dto = (DateTimeOffset)value;
return new DateTime(dto.DateTime.Year, dto.DateTime.Month, dto.DateTime.Day, dto.DateTime.Hour, dto.DateTime.Minute, 0);
}
else return new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 0, 0, 0);
}
}
Поскольку TextBox находится внутри ListView, CommandParameter="{Binding}"
должен быть ModelAgendaReceita
, то есть моделью, которая передает ListSource ItemsView. Событие для команды продолжает передавать TextChangedEventArgs как CommandParameter, и я хочу модель.
РЕДАКТИРОВАТЬ .: Вот фрагмент модели:
public class ModelAgendaReceita : INotifyPropertyChanged
{
public ModelAgendaReceita()
{
}
//Here I create the model based on another model
public ModelAgendaReceita(ModelAgendaReceita p_agendareceita)
{
ID = p_agendareceita.ID;
IDFormaReceita = p_agendareceita.IDFormaReceita;
Data = p_agendareceita.Data;
Valor = p_agendareceita.Valor;
Parcela = p_agendareceita.Parcela;
Recibo = p_agendareceita.Recibo;
Pago = p_agendareceita.Pago;
DataPagamento = p_agendareceita.DataPagamento;
Ativo = p_agendareceita.Ativo;
}
public int ID { get; set; }
public int IDFormaReceita { get; set; }
private DateTime m_data = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 0, 0, 0);
public DateTime Data
{
get { return m_data; }
set { m_data = value; OnPropertyChanged("Data"); }
}
private decimal m_valor;
public decimal Valor
{
get { return m_valor; }
set { m_valor = value; OnPropertyChanged("Valor"); }
}
private int m_parcela;
public int Parcela
{
get { return m_parcela; }
set { m_parcela = value; OnPropertyChanged("Parcela"); }
}
private string m_recibo = string.Empty;
public string Recibo
{
get { return m_recibo; }
set { m_recibo = value; OnPropertyChanged("Recibo"); }
}
private bool m_pago = false;
public bool Pago
{
get { return m_pago; }
set { m_pago = value; OnPropertyChanged("Pago"); }
}
private DateTime m_datapagamento = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 0, 0, 0);
public DateTime DataPagamento
{
get { return m_datapagamento; }
set { m_datapagamento = value; OnPropertyChanged("DataPagamento"); }
}
private bool m_ativo = true;
public bool Ativo
{
get { return m_ativo; }
set { m_ativo = value; OnPropertyChanged("Ativo"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Вот как я объявляю свою ViewModel и Команду внутри нее:
public class HomeVM
{
public DelegateCommand SelecaoSolicitacao { get; set; }
public HomeVM()
{
SelecaoSolicitacao = new DelegateCommand(SelecionarSolicitacao);
}
public void ModificarAgendaReceita(object obj)
{
var p_atual = (ModelAgendaReceita)obj;
var p_inicial = ListaAgendaReceitaInicial.FirstOrDefault(l => l.ID == p_atual.ID);
if (p_inicial != null) p_atual.Status = ModelAgendaReceita.ValidarAlteracao(p_inicial, p_atual);
}
}
Это класс, с которым я делаю свои команды:
public class DelegateCommand : ICommand
{
//These delegates store methods to be called that contains the body of the Execute and CanExecue methods
//for each particular instance of DelegateCommand.
private readonly Predicate<object> _canExecute;
private readonly Action<object> _Execute;
//Two Constructors, for convenience and clean code - often you won't need CanExecute
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
_canExecute = canExecute;
_Execute = execute;
}
public DelegateCommand(Action<object> execute)
: this(execute, null)
{ }
//CanExecute and Execute come from ICommand
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(object parameter)
{
if (!CanExecute(parameter))
return;
_Execute(parameter);
}
/// <summary>
/// Not a part of ICommand, but commonly added so you can trigger a manual refresh on the result of CanExecute.
/// </summary>
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
За которыми я следовал с https://onewindowsdev.com/2016/06/16/the-command-pattern-and-mvvm/.
Кто-нибудь знает, как обойти это? Буду признателен за любой совет / помощь!