在不关闭新视图的情况下向数据网格添加数据(WPF MVVM)CRUD

Add Data to Datagrid Without Closing new View (WPF MVVM) CRUD

我是 MVVM 的新手,我似乎找不到问题的答案..

我有 2 个视图(Caixa 和 CaixaDetalhes),在 Caixa 视图中我有一个显示所有 Caixas 的数据网格,在第二个视图中它显示详细信息,用户可以“CRUD”但我不想关闭使用对话框结果更新或添加时查看。

我的观点:

AssistenciasCaixas:

<DataGrid x:Name="dgCaixas" Grid.Row="1" Style="{StaticResource DataGridResultados}" ItemsSource="{Binding Caixas}" SelectedItem="{Binding CaixaSelecionado}" RowHeight="25" Background="White" >
           <DataGrid.Columns>
               <DataGridTextColumn Header="Id" Visibility="Hidden" Binding="{Binding Id}"/>
               <DataGridTextColumn Header="PostoID" Visibility="Hidden" Binding="{Binding Posto.ID}"/>
               <DataGridTextColumn Header="IdUtilizador" Visibility="Hidden" Binding="{Binding IdUtilizador}"/>
               <DataGridTextColumn Header="Posto" Width="200" Binding="{Binding Posto.Descricao}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True"/>
               <DataGridTextColumn Header="Data Caixa" Width="90" Binding="{Binding DataCaixa,StringFormat={}\{0:dd/MM/yyyy\}}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True"/>
               <DataGridTextColumn Header="Data Eliminado" Width="100" Binding="{Binding DataEliminado, StringFormat={}\{0:dd/MM/yyyy\}}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True"/>
               <DataGridTextColumn Header="Motivo" Width="*" Binding="{Binding Motivo}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True"/>
               <DataGridTextColumn Header="Nº Caixa" Width="70" Binding="{Binding NumCaixa}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True"/>
               <DataGridTextColumn Header="Exportado" Width="100" Binding="{Binding Exportado}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True">
                   <DataGridTextColumn.ElementStyle>
                       <Style TargetType="TextBlock">
                           <Setter Property="HorizontalAlignment" Value="Center" />
                       </Style>
                   </DataGridTextColumn.ElementStyle>
               </DataGridTextColumn>
               <DataGridTextColumn Header="Observações" Width="200" Binding="{Binding Obs}" CanUserReorder="False" CanUserResize="False" CanUserSort="False" FontSize="15" IsReadOnly="True"/>
               <DataGridTextColumn Header="Utilizador" Visibility="Hidden" Binding="{Binding IdUtilizador}"/>
           </DataGrid.Columns>
       </DataGrid>

CaixaDetalhes

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="70"/>
            <RowDefinition Height="80"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="150"/>
            <RowDefinition Height="70"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Content="Posto:" VerticalAlignment="Top" HorizontalAlignment="Center" Style="{StaticResource lblEditarForms}" Margin="0,-5,0,0" />
            <ComboBox Grid.Column="0" x:Name="comboBoxPostos" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="300" Margin="0,0,0,5" Style="{DynamicResource ComboBoxProblemas}" ItemsSource="{Binding Postos}" SelectedItem="{Binding Detalhes.Posto}" SelectedValue="{Binding Detalhes.Posto.ID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="ID" DisplayMemberPath="Descricao"/>
            <Rectangle VerticalAlignment="Stretch" HorizontalAlignment="Right" Width="1" Stroke="#FF00256D" />
            <Label Grid.Column="1" Content="Exportado para o Olisoft?" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="35,0,0,0" Style="{StaticResource lblEditarForms}" FontSize="20"/>
            <CheckBox x:Name="cbExportado" Grid.Column="1" IsChecked="{Binding Detalhes.Exportado, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,20,0">
                <CheckBox.LayoutTransform>
                    <ScaleTransform ScaleX="1.5" ScaleY="1.5" />
                </CheckBox.LayoutTransform>
            </CheckBox>
            <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="1" Stroke="#FF00256D" Grid.ColumnSpan="2" />
        </Grid>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Content="Data do Caixa:" VerticalAlignment="Top" HorizontalAlignment="Center" Style="{StaticResource lblEditarForms}" FontSize="20"/>
            <DatePicker x:Name="dtPickerDataCaixa" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,15" FirstDayOfWeek="Monday" DisplayDateStart="2015-01-01" CalendarStyle="{StaticResource resizedCalendarItem}" SelectedDate="{Binding Detalhes.DataCaixa, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            <Rectangle VerticalAlignment="Stretch" HorizontalAlignment="Right" Width="1" Stroke="#FF00256D" />
            <Label Grid.Column="1" Content="Data Eliminado:" VerticalAlignment="Top" HorizontalAlignment="Center" Style="{StaticResource lblEditarForms}" FontSize="20"/>
            <DatePicker x:Name="dtPickerDataEliminado" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,15" FirstDayOfWeek="Monday" DisplayDateStart="2015-01-01" CalendarStyle="{StaticResource resizedCalendarItem}" SelectedDate="{Binding Detalhes.DataEliminado, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <Rectangle Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Right" Width="1" Stroke="#FF00256D" />
            <Label Grid.Column="2" Content="Número do Caixa:" VerticalAlignment="Top" HorizontalAlignment="Center" Style="{StaticResource lblEditarForms}" FontSize="20"/>
            <TextBox x:Name="txtNumCaixa" Grid.Column="2" Height="28" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,15" Width="200"  MaxLines="1" FontSize="15" Text="{Binding Detalhes.NumCaixa, UpdateSourceTrigger=PropertyChanged}"/>
            <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="1" Stroke="#FF00256D" Grid.ColumnSpan="3" />
        </Grid>
        <Label Grid.Row="2" Content="Motivo" VerticalAlignment="Top" HorizontalAlignment="Center" Style="{StaticResource lblEditarForms}" FontSize="20" Margin="0,-6,0,0"/>
        <TextBox Grid.Row="2" x:Name="richTextBoxMotivo" Height="100" Width="655" FontFamily="Calibri" FontSize="18" VerticalAlignment="Bottom" BorderBrush="#AAAAAA" BorderThickness="1.5" Margin="0,0,0,8" Text="{Binding Detalhes.Motivo, UpdateSourceTrigger=PropertyChanged}"/>
        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="1" Stroke="#FF00256D" Grid.Row="2" />
        <Label Grid.Row="3" Content="Observações" VerticalAlignment="Top" HorizontalAlignment="Center" Style="{StaticResource lblEditarForms}"  FontSize="20" Grid.RowSpan="2"/>
        <TextBox Grid.Row="3" x:Name="richTextBoxObservacoes" Height="100" Width="655" FontFamily="Calibri" FontSize="18" VerticalAlignment="Bottom" BorderBrush="#AAAAAA" BorderThickness="1.5" Margin="0,0,0,10" Text="{Binding Detalhes.Obs, UpdateSourceTrigger=PropertyChanged}" />
        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="1" Stroke="#FF00256D" Grid.Row="3" />
        <UniformGrid Grid.Row="4" Columns="4" Height="70" Background="White" >
            <Button x:Name="btnGravar" Style="{StaticResource BotaoGridOperacoes}" CommandParameter="{Binding}" Command="{Binding Gravar}">
                <DockPanel LastChildFill="True" Width="115">
                    <Image Source="../../Imagens/save32black.png" Stretch="Fill" Width="32" Height="32" />
                    <TextBlock x:Name="txtBtnGravar" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="#FF00256D" Text="{Binding Path=AddSave, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"></TextBlock>
                </DockPanel>
            </Button>
            <Button Style="{StaticResource BotaoGridOperacoes}">
                <DockPanel LastChildFill="True" Width="115">
                    <Image Source="../../Imagens/new32Black.png" Stretch="Fill" Width="32" Height="32"   />
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="#FF00256D">Novo</TextBlock>
                </DockPanel>
            </Button>
            <Button Style="{StaticResource BotaoGridOperacoes}" >
                <DockPanel VerticalAlignment="Stretch" Width="125">
                    <Image Source="../../Imagens/bin2.png" Stretch="Fill" Width="32" Height="32"/>
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="#FF00256D">Eliminar</TextBlock>
                </DockPanel>
            </Button>
            <Button x:Name="btnSair" Style="{StaticResource BotaoGridOperacoes}" CommandParameter="{Binding}" Command="{Binding Sair}">
                <DockPanel VerticalAlignment="Stretch" Width="100">
                    <Image Source="/HelpDesk Assist;component/Avancado/Imagens/exit32.png" Stretch="Fill" Width="32" Height="32"  />
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="#FF00256D">Sair</TextBlock>
                </DockPanel>
            </Button>
        </UniformGrid>
    </Grid>

我的模特:

储蓄银行:

public class Caixa : BaseNotifyPropertyChanged
    {
        private int _id;
        private Posto _posto;
        private DateTime _dataCaixa;
        private DateTime _dataEliminado;
        private string _motivo;
        private int _numCaixa;
        private bool _exportado;
        private string _obs;
        private int _idUtilizador;

        public int Id
        {
            get => _id;
            set => SetField(ref _id, value);
        }

        public Posto Posto
        {
            get => _posto;
            set => SetField(ref _posto, value);
        }

        public DateTime DataCaixa
        {
            get => _dataCaixa;
            set => SetField(ref _dataCaixa, value);
        }

        public DateTime DataEliminado
        {
            get => _dataEliminado;
            set => SetField(ref _dataEliminado, value);
        }

        public string Motivo
        {
            get => _motivo;
            set => SetField(ref _motivo, value);
        }

        public int NumCaixa
        {
            get => _numCaixa;
            set => SetField(ref _numCaixa, value);
        }

        public bool Exportado
        {
            get => _exportado;
            set => SetField(ref _exportado, value);
        }

        public string Obs
        {
            get => _obs;
            set => SetField(ref _obs, value);
        }

        public int IdUtilizador
        {
            get => _idUtilizador;
            set => SetField(ref _idUtilizador, value);
        }
    } 

我的视图模型:

CaixasViewModel

public class CaixasViewModel : BaseNotifyPropertyChanged
    {
        public ObservableCollection<Caixa> Caixas { get; private set; }

        public CaixasViewModel()
        {
            int utilizadorAtual = Properties.Settings.Default.userID;
            Caixas = new ObservableCollection<Caixa>();
            Caixas = CaixaData.GetCaixasUtilizador(utilizadorAtual);
        }

        private Caixa _caixaSelecionado;
        public Caixa CaixaSelecionado
        {
            get { return _caixaSelecionado; }
            set
            {
                SetField(ref _caixaSelecionado, value);
                Delete.RaiseCanExecuteChanged();
                Edita.RaiseCanExecuteChanged();
            }
        }

        public DeleteCaixa Delete { get; private set; } = new DeleteCaixa();
        public EditaCaixa Edita { get; private set; } = new EditaCaixa();
        public NovoCaixa Novo { get; private set; } = new NovoCaixa();

        public class DeleteCaixa : BaseCommand
        {
            public override bool CanExecute(object parameter)
            {
                return parameter is CaixasViewModel viewModel && viewModel.CaixaSelecionado != null;
            }

            public override void Execute(object parameter)
            {
                CaixasViewModel viewModel = (CaixasViewModel)parameter;
                CaixaData.DeleteCaixa(viewModel.CaixaSelecionado.Id);
                _ = viewModel.Caixas.Remove(viewModel.CaixaSelecionado);
            }
        }

        public class NovoCaixa : BaseCommand
        {
            public override bool CanExecute(object parameter)
            {
                return parameter is CaixasViewModel;
            }

            public override void Execute(object parameter)
            {
                CaixasViewModel viewModel = (CaixasViewModel)parameter;
                Caixa caixa = new Caixa
                {
                    DataCaixa = DateTime.Now,
                    DataEliminado = DateTime.Now
                };
                CaixasDetalhesViewModel caixaDetalhes = new CaixasDetalhesViewModel(caixa);
                DetalhesCaixa dc = new DetalhesCaixa(caixaDetalhes)
                {
                    Owner = Application.Current.MainWindow
                };
                _ = dc.ShowDialog();
                if (dc.DialogResult.HasValue && dc.DialogResult.Value)
                {
                    viewModel.Caixas.Add(caixa);
                    viewModel.CaixaSelecionado = caixa;
                }
            }
        }

        public class EditaCaixa : BaseCommand
        {
            public override bool CanExecute(object parameter)
            {
                return parameter is CaixasViewModel viewModel && viewModel.CaixaSelecionado != null;
            }
            public override void Execute(object parameter)
            {
                CaixasViewModel viewModel = (CaixasViewModel)parameter;
                CaixasDetalhesViewModel caixaDetalhes = new CaixasDetalhesViewModel(viewModel.CaixaSelecionado);
                DetalhesCaixa detCaixa = new DetalhesCaixa(caixaDetalhes)
                {
                    Owner = Application.Current.MainWindow
                };
                _ = detCaixa.ShowDialog();
            }
        }
    }

CaixasDetalhesViewModel:

public class CaixasDetalhesViewModel : BaseNotifyPropertyChanged
    {
        public ObservableCollection<Posto> Postos { get; set; }

        public Caixa Detalhes { get; set; }

        public CaixasDetalhesViewModel(Caixa detalhes)
        {
            Postos = new ObservableCollection<Posto>();
            Postos = PostoData.GetPostosSimples();
            Detalhes = detalhes;
            EscolheFinal();
        }

        private string _addSave = "Inserir";
        public string AddSave
        {
            get => _addSave;
            set
            {
                _addSave = value;
                RaisePropertyChanged("AddSave");
            }
        }

        public void EscolheFinal()
        {
            AddSave = Detalhes.Id == 0 ? "Inserir" : "Gravar";
        }

        public Action DialogResult { get; set; }
        public Action CloseWindow { get; set; }

        public GravarCaixa Gravar { get; private set; } = new GravarCaixa();
        public SairCaixa Sair { get; private set; } = new SairCaixa();

        public class GravarCaixa : BaseCommand
        {
            public override bool CanExecute(object parameter)
            {
                return parameter is CaixasDetalhesViewModel viewModel;
            }

            public override void Execute(object parameter)
            {
                CaixasDetalhesViewModel viewModel = (CaixasDetalhesViewModel)parameter;
                viewModel.Detalhes.IdUtilizador = Properties.Settings.Default.userID;
                CaixaData.AdicionaCaixa(viewModel.Detalhes);
                viewModel.EscolheFinal();
                viewModel.DialogResult();

            }
        }

        public class SairCaixa : BaseCommand
        {
            public override bool CanExecute(object parameter)
            {
                return parameter is CaixasDetalhesViewModel viewModel;
            }
            public override void Execute(object parameter)
            {
                CaixasDetalhesViewModel viewModel = (CaixasDetalhesViewModel)parameter;
                viewModel.CloseWindow();

            }
        }

    }

总体:

我可以使用 DialogResult 进行 CRUD,但我需要能够 insert/update/delete 在 CaixaDetalhes 视图中“Caixa”而不关闭视图

编辑: 如何在单击保存按钮时更新 Caixa 模型?我已经尝试使用“UpdateSourceTrigger=Explicit”,但是在尝试更改 Caixa 时没有任何反应..

我没有使用任何框架,如果可能我想保持这种状态

我建议将保存命令和当前修改项的引用从CaixasViewModel传递到CaixasDetalhesViewModel。然后让 CaixasViewModel 修改其 Caixas 集合,因为它是所有者。

您不应显示来自视图模型的对话框。从代码隐藏中显示它(参见下面的示例)。

以下示例应该让您对该模式有一个初步的了解: 让主视图模型使用相应的保存命令和要修改的项目(添加和编辑)创建和初始化对话框视图模型。对话视图模型仅向用户公开要修改的项,并执行从主视图模型接收到的保存命令。主视图模型知道如何处理目标项,例如创建新实例(创建新对话框)或复制实例(编辑对话框)。

主要思想是创建您要编辑的原始项目模型的副本。单击保存按钮时,通过将新数据复制回原始模型(编辑副本)来提交更改。

该示例还利用了可重用的 RelayCommand,通过降低代码复杂性来帮助提高可读性。您可以在 Microsoft Docs: Relaying Command Logic 找到原始实现。只需将短代码复制到项目中名为 RelayCommand 的 class 并使用它,而不是为每个命令执行新命令 classes。

CaixasViewModel.cs

class CaixasViewModel
{
  public ObservableCollection<Caixa> Caixas { get; private set; }

  // The "Save" command of the create dialog.
  public ICommand AddCaixaCommand => new RelayCommand(ExecuteAddCaixa);
  
  // The "Save" command of the edit dialog
  public ICommand UpdateCaixaCommand 
    => new RelayCommand(ExecuteUpdateCaixa, commandParameter => this.CaixaSelecionado != null);

  public ICommand RemoveCaixaCommand => new RelayCommand(ExecuteRemoveCaixa);

  // Clears the current EditSource by creating a new empty Caixa item
  public ICommand NewCaixaCommand => new RelayCommand(ExecuteNewCaixa);

  private CaixasDetalhesViewModel CurrentCaixasDetalhesViewModel { get; set; }

  public CaixasDetalhesViewModel GetEditCaixaViewModel 
  { 
    var editSource = this.CaixaSelecionado.Clone();
    this. CurrentCaixasDetalhesViewModel = 
      new EditCaixasDetalhesViewModel(
        this.ReplaceCaixaCommand, 
        editSource);

    return this.CurrentCaixasDetalhesViewModel;
  }

  public CaixasDetalhesViewModel GetCreateCaixaViewModel 
  { 
    var editSource = new Caixa();
    this.CurrentCaixasDetalhesViewModel = 
      new CreateCaixasDetalhesViewModel(
        this.AddCaixaCommand, 
        this.NewCaixaCommand,
        editSource);

    return this.CurrentCaixasDetalhesViewModel;
  }

  private void ExecuteAddCaixa(object commandParameter) 
  {
    var createdCaixa = (Caixa)commandParameter;
    this.Caixas.Add(createdCaixa);

    // Create a new temp copy to avoid editing the original instance directly    
    var editableCreatedCaixa = createdCaixa.Clone();
    this.CurrentCaixasDetalhesViewModel.EditSource = editableCreatedCaixa;
  }

  private void ExecuteNewCaixa(object commandParameter) 
  {
    // Update the dialog with a new empty Caixa item
    var emptyCaixa = new Caixa();
    this.CurrentCaixasDetalhesViewModel.EditSource = emptyCaixa;
  }

  private void ExecuteUpdateCaixa(object commandParameter)
  {
    Caixa editedCaixa = (Caixa)commandParameter;
    var originalCaixa = this.Caixas.First(caixa => caixa.Id == editedCaixa.Id);
    
    // Copy data
    originalCaixa.Posto = editedCaixa.Posto;
    ...
  }

  private void ExecuteRemoveCaixa(object commandParameter) 
    => this.Caixas.Remove((Caixa)commandParameter);
}

CreateCaixasDetalhesViewModel.cs

class  CreateCaixasDetalhesViewModel : INotifyPropertyChanged
{
  public Caixa EditSource { get; set; }
  public ICommand SaveCommand { get; }
  public ICommand ClearEditSourceCommand { get; }

  public CreateCaixasDetalhesViewModel(
    ICommand saveCommand, 
    ICommand newCommand, 
    Caixa editSource)
  {
    this.SaveCommand = saveCommand;
    this.ClearEditSourceCommand = newCommand;
    this.EditSource = editSource;
  }
}

EditCaixasDetalhesViewModel.cs

class  EditCaixasDetalhesViewModel : INotifyPropertyChanged
{
  public Caixa EditSource { get; set; }
  public ICommand SaveCommand { get; }

  public EditCaixasDetalhesViewModel(
    ICommand saveCommand, 
    Caixa editSource)
  {
    this.SaveCommand = saveCommand;
    this.EditSource = editSource;
  }
}

AssistenciasCaixas.xaml

<!-- DataContext is the CaixasViewModel -->
<Window>
  <StackPanel>
    <DataGrid x:Name="dgCaixas" />

    <Button Content="Open Edit Dialog" Click="OnEditDialogButtonClicked" />
    <Button Content="Open Create New Dialog" Click="OnCreateDialogButtonClicked" />
  </StackPanel>
</Window>

AssistenciasCaixas.xaml.cs

partial class AssistenciasCaixas : Window
{
  private void OnEditDialogButtonClicked(object sender, EventArgs e)
  {    
    var viewModel = this.DataContex as CaixasViewModel;
    CaixasDetalhesViewModel caixaDetalhes = viewModel.GetEditCaixaViewModel();
    var dc = new EditDetalhesCaixa(caixaDetalhes);
    _ = dc.ShowDialog(); // Owner is automatically set on ShowDialog()

    // The following code is now handled in the CaixasViewModel
    //if (dc.DialogResult.HasValue && dc.DialogResult.Value)
    //{
    //  viewModel.Caixas.Add(caixa);
    //  viewModel.CaixaSelecionado = caixa;
    //}
  }

  private void OnCreateDialogButtonClicked(object sender, EventArgs e)
  {    
    var viewModel = this.DataContex as CaixasViewModel;
    CaixasDetalhesViewModel caixaDetalhes = viewModel.GetCreateCaixaViewModel();
    var dc = new CreateDetalhesCaixa(caixaDetalhes);
    _ = dc.ShowDialog(); // Owner is automatically set on ShowDialog()

    // The following code is now handled in the CaixasViewModel
    //if (dc.DialogResult.HasValue && dc.DialogResult.Value)
    //{
    //  viewModel.Caixas.Add(caixa);
    //  viewModel.CaixaSelecionado = caixa;
    //}
  }
}

CreateCaixaDetalhes.xaml

<!-- DataContext is the CreateCaixasDetalhesViewModel -->
<Window>
  <StackPanel>
    <TextBox Text="{Binding EditSource.Motivo}" />
    <Button Content="Save" 
            Command="{Binding SaveCommand}"
            CommandParameter="{Binding EditSource}" />
    <Button Content="New" 
            Command="{Binding ClearEditSourceCommand}" />
  </StackPanel>
</Window>

EditCaixaDetalhes.xaml

<!-- DataContext is the EditCaixasDetalhesViewModel -->
<Window>
  <StackPanel>
    <TextBox Text="{Binding EditSource.Motivo}" />
    <Button Content="Save" 
            Command="{Binding SaveCommand}"
            CommandParameter="{Binding EditSource}" />
  </StackPanel>
</Window>

Caixa.cs

public class Caixa : ICloneable
{
  public int Id
  {
    get => _id;
    set => SetField(ref _id, value);
  }

  ...

  // Assumes that the property Posto is not editable via dialog,
  // otherwise clone Posto too (deep clone). 
  object ICloneable.Clone() => MemberwiseClone();
  public Caixa Clone() => ((ICloneable)this).Clone() as Caixa;
}