在不关闭新视图的情况下向数据网格添加数据(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;
}
我是 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;
}