简体   繁体   中英

How to get the saved Appointment on a DevExpress Scheduler control using WPF and MVVM?

I'm trying to implement a scheduler in WPF using the DevExpress SchedulerControl . What I want to do is at the moment of creating a new appointment, pass the new appointment object to the view model to save it in a database. This is my MainWindow view:

<Grid>
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="Auto"/>
   </Grid.ColumnDefinitions>
   <dxsch:SchedulerControl x:Name="scheduler" ActiveViewType="WeekView" FirstDayOfWeek="Monday" Grid.Column="0">
      <dxsch:SchedulerControl.OptionsWindows>
         <dxsch:OptionsWindows AppointmentWindowType="{x:Type local:CrearTareaWindow}"/>
      </dxsch:SchedulerControl.OptionsWindows>
      <dxmvvm:Interaction.Behaviors>
         <dxmvvm:EventToCommand EventName="AppointmentAdded" Command="{Binding SaveCommand}" />
         <dxmvvm:EventToCommand Command="{Binding DeleteCommand}" EventName="AppointmentRemoved"/>
         <dxmvvm:EventToCommand Command="{Binding EditCommand}" EventName="AppointmentEdited" />
      </dxmvvm:Interaction.Behaviors>
      <dxsch:SchedulerControl.DataSource>
         <dxsch:DataSource AppointmentsSource="{Binding Tareas}">
            <dxsch:DataSource.AppointmentMappings>
               <dxsch:AppointmentMappings
                  Subject="nombre"
                  Description="descripcion"
                  Start="fechaInicio"
                  End="fechaFin">
                  <dxsch:CustomFieldMapping Mapping="custom" Name="custom" />
               </dxsch:AppointmentMappings>
            </dxsch:DataSource.AppointmentMappings>
         </dxsch:DataSource>
      </dxsch:SchedulerControl.DataSource>
   </dxsch:SchedulerControl>
   <dxe:DateNavigator Name="dateNavigator" Grid.Column="1" ShowTodayButton="False">
      <dxe:DateNavigator.StyleSettings>
         <dxsch:SchedulerDateNavigatorStyleSettings Scheduler="{Binding ElementName=scheduler}" />
      </dxe:DateNavigator.StyleSettings>
   </dxe:DateNavigator>
</Grid>

Here I'm calling 3 commands whenever in the scheduler the user adds, deletes or edits a appointment. My ViewModel looks like this:

public class ViewModel: ViewModelBase {
  public List < Tarea > Tareas {
    get =>new List < Tarea > {
      new Tarea {
        nombre = "Cita con el doctor",
        descripcion = "Al PPL le duele la panza",
        fechaInicio = new DateTime(2020, 10, 1, 12, 0, 0),
        fechaFin = new DateTime(2020, 10, 1, 14, 0, 0)
      }
    };
  }

  public ICommand SaveCommand {
    get {
      return new RelayCommand(param =>Save(param));
    }
  }
  void Save(object a) {
    Console.Write(a);
  }

  public ICommand DeleteCommand {
    get {
      return new RelayCommand(param =>Delete(param));
    }
  }
  void Delete(object a) {
    Console.Write("");
  }

  public ICommand EditCommand {
    get {
      return new RelayCommand(param =>Edit(param));
    }
  }
  void Edit(object a) {
    Console.Write(a);
  }
}

I'm using a custom window to save appointments:

<StackPanel Margin="10">
   <TextBlock FontWeight="Bold" Text="Nombre:"/>
   <TextBox Text="{Binding Subject, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
   <TextBlock FontWeight="Bold" Text="Descripción:"/>
   <TextBox Text="{Binding Description, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Height="100"/>
   <TextBlock FontWeight="Bold" Text="Fecha de Inicio:"/>
   <DockPanel>
      <dxe:DateEdit
             x:Name="editorStartDate"
             Width="150"
             DockPanel.Dock="Left"
             Style="{DynamicResource {dxscht:AppointmentWindowThemeKey ResourceKey=Editor_StartDate}}" />
      <dxe:TextEdit
             x:Name="editorStartTime"
             Margin="4,0,0,0"
             DockPanel.Dock="Left"
             Style="{DynamicResource {dxscht:AppointmentWindowThemeKey ResourceKey=Editor_StartTime}}" />
   </DockPanel>
   <TextBlock FontWeight="Bold" Text="Fecha de fin:"/>
   <DockPanel>
      <dxe:DateEdit
             x:Name="editorEndDate"
             Width="150"
             DockPanel.Dock="Left"
             Style="{DynamicResource {dxscht:AppointmentWindowThemeKey ResourceKey=Editor_EndDate}}" />
      <dxe:TextEdit
             x:Name="editorEndTime"
             Margin="4,0,0,0"
             DockPanel.Dock="Left"
             Style="{DynamicResource {dxscht:AppointmentWindowThemeKey ResourceKey=Editor_EndTime}}" />
   </DockPanel>
   <TextBlock FontWeight="Bold" Text="Custom:"/>
   <TextBox Text="{Binding CustomFields.custom, Mode=TwoWay}"/>
   <Grid Margin="0 10">
      <Grid.Resources>
         <Style TargetType="Button">
            <Setter Property="Margin" Value="0 0 10 0"/>
         </Style>
      </Grid.Resources>
      <Grid.ColumnDefinitions>
         <ColumnDefinition/>
         <ColumnDefinition/>
         <ColumnDefinition/>
      </Grid.ColumnDefinitions>
      <Button Grid.Column="0" Content="GUARDAR" Command="{Binding SaveAndCloseAppointmentCommand}"/>
      <Button Grid.Column="1" 
             Content="BORRAR" 
             CommandParameter="{Binding ElementName=scheduler, Path=SelectedAppointments[0]}"
             Command="{Binding RemoveAppointmentCommand}"/>
      <Button Grid.Column="2" Content="CANCELAR" Command="{Binding CancelEditingCommand}"/>
   </Grid>
</StackPanel>

The problem is that I don't found a way to pass the created, edited or delete appointment to the command as parameter. I don't found nothing related in the documentation. The commands is called correctly when I add or delete but I don't found a way to get the appointment object that is added or deleted. How can I do this?

SOLUTION UPDATE

The first solution of that guy worked fine but I had problems with the second one. The problem is that AppointmentItem don't have a DataContext property so I have to do some changes to the converter:

protected override object Convert(object sender, AppointmentAddedEventArgs args) {
  AppointmentItem appointmentItem = args.Appointments.FirstOrDefault();
  Tarea tarea = new Tarea {
    nombre = appointmentItem.Subject,
    descripcion = appointmentItem.Description,
    fechaInicio = appointmentItem.Start,
    fechaFin = appointmentItem.End,
    EtiquetaId = (int ? ) appointmentItem.LabelId,
    custom = appointmentItem.CustomFields["custom"].ToString()
  };
  return tarea;
}

And in the ViewModel just take the Appointment object like this:

void Save(object a) {
  Tarea tarea = (Tarea) a;
  Console.Write(tarea);
}

With this I get the added appointment in the ViewModel.

Each of the events has an associated event args type.

These event args each contain a collection of affected appointments in the Appointments property. You can pass these event args as CommandParameter automatically by setting PassEventArgsToCommand="True" , eg:

<dxmvvm:EventToCommand EventName="AppointmentAdded"
                       Command="{Binding SaveCommand}"
                       PassEventArgsToCommand="True"/>

Now, you could just cast the object passed to the corresponding command to the associated event args type and access the Appointments property, eg for added appointments:

void Save(object a) {
   var args = (AppointmentAddedEventArgs)a;
   var appointments = args.Appointments;
   
   // ...do something with the appointments.
}

This solves your problem, but is not good, as the event args are user interface related an should not be passed into the view model. However, there is a solution to this, as you can create an event args converter. See an example in the documentation .

You would create a converter for the target event type. As the Appointments collection contains AppointmentItem items, which are UI containers, you could extract your underlying data items of type Tarea with Linq by returning their SourceObject like this.

public class AppointmentAddedEventArgsConverter : EventArgsConverterBase<AppointmentAddedEventArgs>
{
   protected override object Convert(object sender, AppointmentAddedEventArgs args)
   {
      return args.Appointments.Select(ai => ai.SourceObject).Cast<Tarea>();
   }
}

Then you can assign it in XAML like this and it will automatically pass an enumerable of your Tarea items as command parameter to your command.

<dxmvvm:EventToCommand EventName="AppointmentAdded"
                       Command="{Binding SaveCommand}">
   <dxmvvm:EventToCommand.EventArgsConverter>
      <local:AppointmentAddedEventArgsConverter />
   </dxmvvm:EventToCommand.EventArgsConverter>
<dxmvvm:EventToCommand/>

In your execute delegate, you can directly cast the command parameter to the extracted item collection.

void Save(object a) {
   var addedTareas = (IEnumerable<Tarea>)a;

   // ...do something with the added items.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM