1

我有一个简单的 View 和 ViewModel。当您单击技术人员组合框并选择技术人员时,选定技术人员的测试将显示在您在下面看到的列表视图中。这工作得很好。

注意Technician 与 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);
        }
    }
}

顺便说一句,为了测试 DataBinding 上的功能ObservableCollection<Technician> Technicians;,正如您在上面的 ViewModel 中看到的那样,我通过 SSMS 进入数据库并在应用程序仍在运行时添加了一个新的 Technician。添加完成后,我转到应用程序并单击我的技术人员组合框,却发现列表/用户界面尚未更新。然而,我会认为,因为我将属性 Technicians 设为 ObservableCollection,并且会引发OnPropertyChanged("Technicians");,所以 UI 会更新。

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

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

第二个问题:我需要添加什么才能让 Technicians 的集合不断了解 DB 更改?(我认为这就是 ObservableCollection 的用途)

4

2 回答 2

3

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

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

制作即时变化感知系统比这更复杂。坦率地说,如果您真的需要即时更新,我建议您查看 pub/sub 之类的内容。否则,也许考虑偶尔轮询。

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

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

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

于 2013-04-03T21:38:51.583 回答
2

除了 Marc Gravell 的回答之外,在回答您的第二个问题时,您可能还想查看该SqlDependency课程。

引用文档

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

于 2013-04-03T21:44:40.727 回答