web-dev-qa-db-fra.com

Mise à jour de la source WPF DataGrid sur la cellule modifiée

Je suis nouveau sur WPF et je l’utilise pour construire un système de point de vente.

J'ai un contrôle DataGrid dans la fenêtre principale lié à un ObservableCollection de Item, le caissier entrera/scannera les articles à vendre. La quantité par défaut pour chaque article est 1, mais le caissier peut modifier la quantité manuellement.

Chaque fois que je change la quantité, il convient de mettre à jour le prix total avec la somme des prix des articles lorsque je laisse la cellule à une autre cellule de la ligne, mais cela n'arrive pas, la source est mise à jour uniquement lorsque je passe à une autre ligne. pas une autre cellule dans la même rangée.

Est-il possible de forcer la DataGrid à mettre à jour le source lorsque la cellule est modifiée plutôt que la ligne?

20
Khaled

Oui, c'est possible Votre question est fondamentalement la même que DataGrid - changer le comportement de l’édition

Le code ci-dessous provient principalement de la réponse de Quartermeister, mais j'ai ajouté un DependencyProperty BoundCellLevel que vous pouvez définir lorsque vous avez besoin d'une liaison DataGrid à mettre à jour lorsque la cellule en cours change.

public class DataGridEx : DataGrid
{
    public DataGridEx()
    {

    }

    public bool BoundCellLevel
    {
        get { return (bool)GetValue(BoundCellLevelProperty); }
        set { SetValue(BoundCellLevelProperty, value); }
    }

    public static readonly DependencyProperty BoundCellLevelProperty =
        DependencyProperty.Register("BoundCellLevel", typeof(bool), typeof(DataGridEx), new UIPropertyMetadata(false));

    protected override Size MeasureOverride(Size availableSize)
    {
        var desiredSize = base.MeasureOverride(availableSize);
        if ( BoundCellLevel )
            ClearBindingGroup();
        return desiredSize;
    }

    private void ClearBindingGroup()
    {
        // Clear ItemBindingGroup so it isn't applied to new rows
        ItemBindingGroup = null;
        // Clear BindingGroup on already created rows
        foreach (var item in Items)
        {
            var row = ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
            row.BindingGroup = null;
        }
    }
}
3
grantnz

Appliquez le UpdateSourceTrigger=LostFocus à chaque liaison. Cela a fonctionné comme un charme pour moi.

<DataGridTextColumn Header="Name" Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" />
55
Almund

Le code de la réponse acceptée ne fonctionnait pas pour moi car la ligne extraite de ItemContainerGenerator.ContainerFromItem(item) donnait la valeur null et que la boucle était assez lente.

Une solution plus simple à la question est le code fourni ici: http://codefluff.blogspot.de/2010/05/commiting-bound-cell-changes.html

private bool isManualEditCommit;
private void HandleMainDataGridCellEditEnding(
  object sender, DataGridCellEditEndingEventArgs e) 
{
 if (!isManualEditCommit) 
 {
  isManualEditCommit = true;
  DataGrid grid = (DataGrid)sender;
  grid.CommitEdit(DataGridEditingUnit.Row, true);
  isManualEditCommit = false;
 }
}
9
mattanja

Almund a raison. UpdateSourceTrigger=LostFocus fonctionnera mieux dans votre cas. Et comme vous avez mentionné que votre source est mise à jour lorsque vous passez à la ligne suivante, cela signifie que vous utilisez probablement ObservableCollection<T> pour lier votre DataGrid's ItemSource. Parce que c'est ce dont vous avez besoin pour réaliser ce que vous voulez.

<DataGridTextColumn Header="Quantity" Binding="{Binding Quantity,
                    Mode=TwoWay, UpdateSourceTrigger=LostFocus}" />
<DataGridTextColumn Header="Total Price" Binding="{Binding TotalPrice,
                    Mode=TwoWay, UpdateSourceTrigger=LostFocus}" />

Vous devez ajouter "UpdateSourceTrigger=LostFocus" à chacune de vos colonnes.

1
Mitesh