Question

This is probably a newbie question but I’m breaking my head about this one. I’m building an application in WPF using the MVVM pattern. I have a view which has fields binded a property exposing the current customer entity. And within the view I have a command to change the bank account numbers belonging to that customer. The command called take the whole sub-entity as parameter. Then call another function which also takes the sub-entity as parameter and passes it to a new viewmodel binded to a new view which is displayd as a dialog for change. This all works. But when I’m change the bank account number in the dialog the original view also changes the account number number real-time. They are still connected to each other. I want to cancel this link to be able to cancel the dialog and the changes I made within that dialog. But I can’t get this to work.

Code say’s more the words.

View MAIN

<dxlc:LayoutGroup Header="Rekeningen" View="GroupBox" Orientation="Vertical"  VerticalAlignment="Stretch">
    <dxlc:LayoutItem>
        <StackPanel>
            <Button Content="{x:Static language:Common.NieuwRekeningnrToevoegen}" Command="{Binding NieuwRekeningCommand}" />
            <ListView ItemsSource="{Binding CurrentRelatie.Rekeningnummers}" ItemTemplate="{StaticResource RelatieRekeningnrTemplate}" />
        </StackPanel>
    </dxlc:LayoutItem>
</dxlc:LayoutGroup>

View item template MAIN

<DataTemplate x:Key="RelatieRekeningnrTemplate">
    <Grid>
        <TextBlock >
            <Run Text="{Binding Omschrijving}" FontWeight="Bold" FontStyle="Italic" /> <LineBreak/>
            <Run Text="{Binding RekNummer}" /> - <Run Text="{Binding BicNummer}" FontStyle="Italic" />
        </TextBlock>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top">
            <Button Command="{Binding DataContext.VerwijderRekeningCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}">
                <Button.Style>
                    <Style TargetType="{x:Type Button}">
                        <Setter Property="Background" Value="{x:Null}" />
                        <Setter Property="BorderBrush" Value="{x:Null}" />
                        <Setter Property="BorderThickness" Value="1" />
                        <Setter Property="Template" Value="{DynamicResource tplFlatButton}" />
                    </Style>
                </Button.Style>
                <Path Height="9" Stretch="Uniform" Fill="{DynamicResource AccentColorDarkGray}" Data="{DynamicResource Delete}" />
            </Button>
            <Button Command="{Binding DataContext.EditRekeningCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}">
                <Button.Style>
                    <Style TargetType="{x:Type Button}">
                        <Setter Property="Background" Value="{x:Null}" />
                        <Setter Property="BorderBrush" Value="{x:Null}" />
                        <Setter Property="BorderThickness" Value="1" />
                        <Setter Property="Template" Value="{DynamicResource tplFlatButton}" />
                    </Style>
                </Button.Style>
                <Path Height="10" Stretch="Uniform" Fill="{DynamicResource AccentColorDarkGray}" Data="{DynamicResource Edit}" >
                </Path>
            </Button>
        </StackPanel>
    </Grid>
</DataTemplate>

Viewmodel

private model.Relatie _CurrentRelatie = null;
public model.Relatie CurrentRelatie
{
    get { return _CurrentRelatie; }
    set { SetProperty(ref _CurrentRelatie, value, () => CurrentRelatie); }
}

public ICommand EditRekeningCommand { get; private set; }
void OnEditRekeningExecute(model.Rekeningnummer Rek)
{
    EditRekeningnummer(Rek);
}

private void EditRekeningnummer(model.Rekeningnummer Rek)
{
    Dialog.dRekeningnummerEditViewModel ReknummerVM = new Dialog.dRekeningnummerEditViewModel();
    ReknummerVM.SetRekening(Rek);

    UICommand ResCommand = DialogService.ShowDialog(ReknummerVM.DialogUICommand, string.Format("{0} {1}", Common.Rekening, Rek.Omschrijving ?? Rek.RekNummer), "viewdRekeningnummerEdit", ReknummerVM);
    if (ResCommand == null || ResCommand.IsCancel == true)
        return;
}

View RekeningnummerEdit

<dxlc:LayoutGroup Orientation="Vertical">

    <dxlc:LayoutItem Label="{Binding CurrentRekening, ConverterParameter=Omschrijving, Converter={StaticResource ModelToDisplay}}">
        <dxe:TextEdit EditValue="{Binding CurrentRekening.Omschrijving, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ValidateOnTextInput="True" utils:FocusAdvancement.AdvancesByEnterKey="true"/>
    </dxlc:LayoutItem>

    <dxlc:LayoutItem Label="{Binding CurrentRekening, ConverterParameter=RekNummer, Converter={StaticResource ModelToDisplay}}">
        <dxe:TextEdit EditValue="{Binding CurrentRekening.RekNummer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ValidateOnTextInput="True" utils:FocusAdvancement.AdvancesByEnterKey="true"/>
    </dxlc:LayoutItem>

    <dxlc:LayoutItem Label="{Binding CurrentRekening, ConverterParameter=BicNummer, Converter={StaticResource ModelToDisplay}}">
        <dxe:TextEdit EditValue="{Binding CurrentRekening.BicNummer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ValidateOnTextInput="True" utils:FocusAdvancement.AdvancesByEnterKey="true"/>
    </dxlc:LayoutItem>

</dxlc:LayoutGroup>

Viewmodel RekeningnummerEdit

public dRekeningnummerEditViewModel()
{ 
DialogUICommand = new List<UICommand>();

    AnnuleerUICommand = new UICommand() {
        Caption=Common.Annuleren,
         Id = MessageBoxResult.Cancel,
         IsCancel=true
    };

    OKUICommand = new UICommand() {
        Caption=Common.Opslaan,
         Id = MessageBoxResult.OK,
         IsDefault=true
    };
    DialogUICommand.Add(OKUICommand);
    DialogUICommand.Add(AnnuleerUICommand);

    CurrentRekening = new model.Rekeningnummer();
}



public void SetRekening(model.Rekeningnummer Rek)
{
    CurrentRekening = Rek;
    IsInEditMode = true;
}

#region "Properties"
private model.Rekeningnummer _CurrentRekening;
public model.Rekeningnummer CurrentRekening
{
    get { return _CurrentRekening; }
    set { SetProperty(ref _CurrentRekening, value, () => CurrentRekening); }
}

#endregion

#region "Private function"


#endregion

#region "Commands"

public List<UICommand> DialogUICommand { get; private set; }
protected UICommand AnnuleerUICommand { get; private set; }
protected UICommand OKUICommand { get; private set; }
Was it helpful?

Solution

The behaviour you're seeing is because you are passing an object reference (model.Rek) from your view to your dialog. Therefore when your dialog changes the values of the model.Rek, the changes are immediately reflected in your view.

A common approach to solve this problem is to:

  1. Clone (copy) your model, i.e. make a new object with the same values. You can use the ICloneable interface as a standard pattern (MemberwiseClone can help here if you only need a shallow copy)
  2. Send the clone to your dialog
  3. If the user presses OK, then take the values of the clone and copy them back to the original model. If the user presses Cancel, then do nothing more
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top