为什么我的属性不知道直接对数据库进行的更改

时间:2013-04-03 21:35:56

标签: c# wpf entity-framework mvvm ef-code-first

我有一个简单的View和ViewModel。当您单击ComboBox of Technicians并选择技术人员时,SelectedTechnician的测试将显示在您看到的ListView中。这非常有效。

注意技术人员与Test有一对多的关系,每个人都是一个实体(代码优先实体框架)。

MainViewModel.xaml

<Grid>
    <StackPanel>
        <ComboBox ItemsSource="{Binding Technicians, Mode=TwoWay}"
                  DisplayMemberPath="FullName"
                  SelectedItem="{Binding SelectedTechnician, Mode=TwoWay}">
        </ComboBox>
        <ListView ItemsSource="{Binding SelectedTechnician.Tests}"
                  SelectedItem="{Binding SelectedTest}"
                  HorizontalAlignment="Left" Height="100" Margin="10,10,0,0" VerticalAlignment="Top" Width="271">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Id" Width="auto" DisplayMemberBinding="{Binding Id}"/>
                    <GridViewColumn Header="Test" Width="auto" DisplayMemberBinding="{Binding TestTypeName}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </StackPanel>
</Grid>

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase
{
    private WpfTestBedDb db = new WpfTestBedDb();

    public MainWindowViewModel()
    {
        Technicians = new ObservableCollection<Technician>();
    }

    private ObservableCollection<Technician> _technicians;

    public ObservableCollection<Technician> Technicians
    {
        get { return _technicians; }
        set
        {
            _technicians = value;
            OnPropertyChanged("Technicians");
        }
    }

    private Technician _selectedTechnician;

    public Technician SelectedTechnician
    {
        get { return _selectedTechnician; }
        set
        {
            if (_selectedTechnician != value)
            {
                _selectedTechnician = value;
                OnPropertyChanged("SelectedTechnician");
            }
        }
    }

    public void LoadTechnicians()
    {
        var query = from tech in db.Technicians
                    select tech;
        foreach (var technician in query)
        {
            Technicians.Add(technician);
        }
    }
}

顺便说一句,要在ObservableCollection<Technician> Technicians;上测试DataBinding的功能,正如您在上面的ViewModel中看到的那样,我通过SSMS进入了数据库,并在应用程序仍在运行时添加了一名新的技术人员。添加完成后,我转到应用程序并单击我的ComboBox of Technicians,发现列表/ UI尚未更新。然而,我会想到,因为我已经使属性技术人员成为ObservableCollection,并且提升了OnPropertyChanged("Technicians");,UI将更新。

我做了这个实验来模拟同时运行的两个相同的应用程序,每个应用程序都读取和写入同一个数据库。

第一个问题:尽管我的ObservableCollection引用了OnPropertyChanged,为什么UI不更新?也就是说,为什么它不知道直接对数据库进行的更改(在应用程序之外)?

第二个问题:我需要添加什么才能让技术人员的集合始终了解数据库更改? (我认为这就是ObservableCollection的用途)

2 个答案:

答案 0 :(得分:3)

简短版本:大多数数据访问代码是已断开连接的模型,而非实时/已连接模型。

这里的“可观察”意味着“对该层中的其他变化做出反应”,即操纵对象模型的其他.NET代码。使用ObservableCollection<T>不会让巨手从数据库通过网络伸出来调整位数。

即时更改感知系统比这更复杂;坦率地说,如果你真的需要即时更新,我会建议看看像pub / sub这样的东西。否则,或许偶尔会考虑轮询。

此外,请注意,如果执行想要进行轮询,则不能仅通过以下方式重新获取对象:

var stateNow = db.Technicians.Single(x => x.Id == myId);

因为可能只是将你已经拥有的同一对象交给你了;很多ORM都内置了身份缓存。要实际重新获取对象,您需要第二个db-context实例。

答案 1 :(得分:2)

除了Marc Gravell的回答,并回答第二个问题,您可以查看SqlDependency课程。

引自the documentation

  

SqlDependency对象表示应用程序与SQL Server实例之间的查询通知依赖关系。应用程序可以创建SqlDependency对象并注册以通过OnChangeEventHandler事件处理程序接收通知。