0
votes

I have a pretty straight-forward MVVM Master\Detail window -

XAML snippet:

        <Grid Grid.Row="0" Grid.Column="0" >
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Label Content="ID:" Grid.Row="0" Grid.Column="0"/>
            <Label Content="{Binding SelectedCustomer.CustId}" Grid.Row="0" Grid.Column="1"/>

            <Label Content="Name:" Grid.Row="1" Grid.Column="0"/>
            <TextBox Text="{Binding SelectedCustomer.Name}"  Grid.Row="1" Grid.Column="1"/>

            <Label Content="Address:" Grid.Row="2" Grid.Column="0"/>
            <TextBox Text="{Binding SelectedCustomer.Address}"  Grid.Row="2" Grid.Column="1"/>
            <Label Content="City:" Grid.Row="3" Grid.Column="0"/>
            <TextBox Text="{Binding SelectedCustomer.City}"  Grid.Row="3" Grid.Column="1"/>
            <Label Content="State:" Grid.Row="4" Grid.Column="0"/>
            <TextBox Text="{Binding SelectedCustomer.State}"  Grid.Row="4" Grid.Column="1"/>
            <Label Content="ZIP:" Grid.Row="5" Grid.Column="0"/>
            <TextBox Text="{Binding SelectedCustomer.ZIP}"  Grid.Row="5" Grid.Column="1"/>

        </Grid>

        <Grid Grid.Row="1" Grid.Column="0">
            <DataGrid ItemsSource="{Binding CustomerCollection}" SelectedItem="{Binding SelectedCustomer}"></DataGrid>
        </Grid>
    </Grid>

Nothing really fancy in the Model:

    public ObservableCollection<Customer> CustomerCollection { get; set; }

    private Customer _selectedCustomer;
    public Customer SelectedCustomer
    {
        get
        {
            return _selectedCustomer;
        }
        set
        {
            _selectedCustomer = value;
            OnPropertyChanged("SelectedCustomer");
        }
    }

I can select a Master row and the detail will fill in appropriately. That part works great.

My problem comes when I edit the Detail, it changes the Master before the user hits Save. If I change one of the properties and it looses focus the databinding will set the Master row to be the same as the new information. I have tried various versions of Mode=OneWay and they don't help.

How do I make the databinding for the SelectedItem only go from the datagrid out, not back in? I will refresh the datagrid when the user clicks Save, that's not an issue. It's more important to me that the record not change mid-stream than to refresh the grid too often.

2

2 Answers

1
votes

You have to set the OneTime binding on the properties of the collection, not the collection itself. Try disabling autogeneratecolumns on your grid and define the columns yourself with a onetime binding. That should get the behavior you need.

Something like this (not tested):

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Customers}" SelectedItem="
     {Binding SelectedCustomer}">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name, Mode=OneTime}" />
        <DataGridTextColumn Binding="{Binding Address, Mode=OneTime}" />
    </DataGrid.Columns>
</DataGrid>

If you really want to separate detail from master though, i recommend having a separate selectedCustomer property and copy that one to the collection bound to the grid when you are done editing. The onetime binding is nice, but you have to update your grid manually, which takes a bit of code if you want to work with strict MVVM. Also note that when you edit the detail, the SelectedCustomer will still be updated on your collection in the ViewModel, the grid just won't reflect the changes yet. So if you hit save the latest information would still be written to the DB.

0
votes

You can use UpdateSourceTrigger But in this case you have to run thru all controls in detail form and manually update the source.

More complex solution is you can load selected row in to detail form not from grid but from server again.