C#Master Detail View - 恢复未保存的更改

时间:2017-02-01 13:43:32

标签: c# wpf mvvm caliburn.micro

我正在使用Caliburn.Micro在C#中创建CRUD应用程序,我有一些看起来像这样的Master Detail View:

我想要实现的是,当我进行一些更改(例如我将容量从47更改为50),然后选择其他位置时,让我们说放置4 并选择再次放置5 我的容量将是47,而不是现在的50。

我正在考虑OneTime绑定,然后手动触发绑定到viewmodel,但是viewModel应该不知道该视图,所以这似乎是一个坏主意。我的代码如下。

XAML:

<DataGrid x:Name="Places"
          Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"
          Width="290"
          HorizontalAlignment="Left"
          CanUserReorderColumns="False" CanUserResizeColumns="False" IsReadOnly="True"
          AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="False" SelectionMode="Single">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Place" Binding="{Binding Name, Mode=OneTime}" MinWidth="150"
                            Width="SizeToCells" />
    </DataGrid.Columns>
</DataGrid>
<Grid Grid.Column="0" Grid.Row="2"
      Width="290" Height="210"
      HorizontalAlignment="Left" VerticalAlignment="Bottom">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="110" />
        <ColumnDefinition Width="180" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
        <RowDefinition Height="60" />
        <RowDefinition Height="30" />
        <RowDefinition Height="60" />
    </Grid.RowDefinitions>

    <Label Content="ID"
           Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" />
    <Label Content="Place*"
           Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />
    <Label Content="Address*"
           Grid.Column="0" Grid.Row="2" VerticalAlignment="Top" />
    <Label Content="Capacity*"
           Grid.Column="0" Grid.Row="3" VerticalAlignment="Top" />
    <Label Content="Comments"
           Grid.Column="0" Grid.Row="4" VerticalAlignment="Top" />

    <TextBox x:Name="SelectedPlace_Id"
             Grid.Column="1" Grid.Row="0" VerticalAlignment="Top"
             IsEnabled="False" />
    <TextBox x:Name="SelectedPlace_Name"
             Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" />
    <TextBox x:Name="SelectedPlace_Address"
             Grid.Column="1" Grid.Row="2"
             Height="55" VerticalAlignment="Top"
             TextWrapping="Wrap" />
    <TextBox x:Name="SelectedPlace_Capacity"
             Grid.Column="1" Grid.Row="3" VerticalAlignment="Top" />
    <TextBox x:Name="SelectedPlace_Comments"
             Grid.Column="1" Grid.Row="4" Height="55"
             VerticalAlignment="Top"
             TextWrapping="Wrap" />
</Grid>
<Button x:Name="DeletePlace" Content="Delete"
        Grid.Column="0" Grid.Row="3"
        Width="100" Height="30" Margin="0 0 110 0"
        HorizontalAlignment="Right" VerticalAlignment="Top" />
<Button x:Name="SavePlace" Content="Save"
        Grid.Column="0" Grid.Row="3"
        Width="100" Height="30" Margin="0 0 5 0"
        HorizontalAlignment="Right" VerticalAlignment="Top" />

视图模型:

    class PlacesTabViewModel : TabViewModel
{ 
    #region Fields

    private BindableCollection<Place> _places;
    private Place _selectedPlace;

    #endregion

    #region Methods

    public PlacesTabViewModel()
    {
        using (var ctx = new DbCtx(App.DatabasePath))
        {
            _places = new BindableCollection<Place>(ctx.Places.OrderBy(p => p.Name));
        }
    }

    public override string ToString()
    {
        return "Places";
    }

    #endregion

    #region Events

    public bool CanDeletePlace => _selectedPlace != null;

    public bool CanSavePlace => (_selectedPlace != null) && _selectedPlace.IsValid();

    public void DeletePlace()
    {
        using (var ctx = new DbCtx(App.DatabasePath))
        {
            try
            {
                ctx.Entry(SelectedPlace).State = EntityState.Deleted;
                ctx.SaveChanges();
            }
            catch (DbUpdateException)
            {
                //TODO: Error
                return;
            }

            Places.Remove(SelectedPlace);

            NotifyOfPropertyChange(nameof(Places));
            NotifyOfPropertyChange(() => CanDeletePlace);
            NotifyOfPropertyChange(() => CanSavePlace);
        }
    }

    public void SavePlace()
    {
        using (var ctx = new DbCtx(App.DatabasePath))
        {
            try
            {
                ctx.Places.Attach(_selectedPlace);
                ctx.Entry(_selectedPlace).State = EntityState.Modified;
                ctx.SaveChanges();
            }
            catch
            {
                //TODO: Error
            }

            NotifyOfPropertyChange(nameof(Places));
        }
    }

    #endregion

    #region Properties

    public BindableCollection<Place> Places
    {
        get { return _places; }
        set
        {
            if (value != _places)
            {
                _places = value;
                NotifyOfPropertyChange(nameof(Places));
            }
        }
    }

    public Place SelectedPlace
    {
        get { return _selectedPlace; }
        set
        {
            if (value != _selectedPlace)
            {
                _selectedPlace = value;

                if (_selectedPlace != null) 
                {
                    _selectedPlace.PropertyChanged += (sender, args) =>
                    {
                        NotifyOfPropertyChange(() => CanSavePlace);
                    };
                }

                NotifyOfPropertyChange(nameof(SelectedPlace));
                NotifyOfPropertyChange(() => CanDeletePlace);
                NotifyOfPropertyChange(() => CanSavePlace);
            }
        }
    }

    #endregion
}

MainWindow的ViewModel

class MainWindowViewModel : PropertyChangedBase
{
    #region Fields

    private BindableCollection<TabViewModel> _tabs = new BindableCollection<TabViewModel>();

    #endregion

    public MainWindowViewModel()
    {
        _tabs.Add(new PlacesTabViewModel());
    }

    #region Properties

    public BindableCollection<TabViewModel> Tabs
    {
        get { return _tabs; }
        set
        {
            if (value != _tabs)
            {
                _tabs = value;
                NotifyOfPropertyChange(nameof(Tabs));
            }
        }
    }

    #endregion
}

1 个答案:

答案 0 :(得分:1)

WPF并不知道普通属性。您必须使其成为依赖项属性,或者在您的情况下,您的VM必须实现INotifyPropertyChanged。当值更改时,它将自动更新。

您可能没有为 SelectedPlace_Capacity 应用INotifyPropertyChanged属性。

我认为这就是问题所在。