在MVVM场景中,应如何轮询数据库表以获取“实时”视图?

教授

我有一个日志数据库表,我想在中显示GridView我已经有一个视图模型,该模型轮询数据库并ObservableCollection在表已更改的情况下更新整个数据库我对这些数据不做任何其他事情,因此我认为不需要进一步的反向模型。

但是,现在我开始认为,除了视图和模型之外,viewmodel不能对其他任何东西进行任何工作是不恰当的,我应该引入一个模型来观察数据库并为viewmodel提供任何更改。然后ObservableCollection,在视图模型中更新的视图会将新数据传达给DataGrid视图中的。

米科·维塔拉(Mikko Viitala)

的确,您ViewModel不应该做“模型”所负责的任何工作,在这种情况下,是数据访问。

确实有很多方法可以实现此目的,但是我将repository pattern围绕您的数据库相关逻辑进行实现。然后将repository依赖项注入您的中ViewModel

这两个家伙如何交流又是另一个故事。您可以不时地使用Task.Run()不阻塞UI的类似方法要求新数据

或者,如果你喜欢,你可以做一个单独的“库轮询”,通知ViewModel当数据被质疑,经eventspub/sub和什么,而不是。

因此repository,绕过Plain strings的最小模拟可能看起来像这样。

// repository 
public interface IRepository<T>
{
    Task<IEnumerable<T>> GetAll();
}

// repository impl
public class SimpleRepository : IRepository<string>
{
    private readonly IList<string> _items = new List<string>();

    public SimpleRepository()
    {}

    public Task<IEnumerable<string>> GetAll()
    {
        if (_items.Count > 10)
            _items.Clear();
        _items.Add(string.Format("string{0}", _items.Count));

        Thread.Sleep(250); // queries take some time...
        return Task.FromResult((IEnumerable<string>) _items);
    }
}

例如,只有GetAll()一种方法可以从存储库中返回所有“记录”。

现在您相关的人ViewModel可以按以下方式使用此存储库。

// ViewModelBase just implements the INotifyPropertyChanged
public class MainViewViewModel : ViewModelBase
{
    private ObservableCollection<string> _items;

    public MainViewViewModel()
        : this(new SimpleRepository())
    {}

    // pass in the repository dependency
    public MainViewViewModel(IRepository<string> simpleRepository)
    {
        SimpleRepository = simpleRepository;
        Task.Run(async () =>
            {
                // sophisticated polling logic here
                while (true)
                {
                    // update collection
                    var results = await SimpleRepository.GetAll();
                    Items = new ObservableCollection<string>(results);
                    Thread.Sleep(250);
                }
            });
    }

    public IRepository<string> SimpleRepository { get; set; }

    public ObservableCollection<string> Items
    {
        get { return _items; }
        set { _items = value; OnPropertyChanged();}
    }
}

因此,这将ObservableCollection<T>不时更新,现在逻辑已超出范围ViewModelXAML如果您想进行测试,请在下面相关

<Window x:Class="WpfApplication1.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModel="clr-namespace:WpfApplication1.ViewModel"
        Title="MainWindow"
        Height="300"
        Width="250">
    <Window.DataContext>
        <viewModel:MainViewViewModel />
    </Window.DataContext>

    <Grid Margin="10">
        <ItemsControl ItemsSource="{Binding Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}"></TextBlock>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

而且它肯定看起来,感觉和表现专业!:)

图片


如果您也想从中承担投票责任ViewModel,那么您RepositoryPoller可以将自己表现为

// generic poller
public class RepositoryPoller<T>
{
    public event EventHandler<RepositoryEventArgs<T>> OnQueryComplete;
    private readonly System.Timers.Timer _timer;
    private TimeSpan _timeSpan;

    // wire-up poll timer
    public RepositoryPoller()
    {
        _timer = new System.Timers.Timer();
        _timer.Elapsed += (sender, args) => Query();
    }

    // provide poll interval and repository, or set via properties
    public RepositoryPoller(TimeSpan timeSpan, IRepository<T> repository)
        :this()
    {
        TimeSpan = timeSpan;
        Repository = repository;
    }

    public TimeSpan TimeSpan
    {
        get { return _timeSpan; }
        set { _timeSpan = value; _timer.Interval = _timeSpan.TotalMilliseconds; }
    }

    public IRepository<T> Repository { get; set; }

    public void Start()
    {
        if (TimeSpan.TotalMilliseconds > 0)
            _timer.Start();
    }

    public void Stop()
    {
        _timer.Stop();
    }

    // query for data
    private async void Query()
    {
        var results = (await Repository.GetAll()).ToArray();
        RaiseQueryCompleted(results);
        NotifyQueryCompleted(results);
    }

    // send results as event
    private void RaiseQueryCompleted(IEnumerable<T> results)
    {
        var handler = OnQueryComplete;
        if (handler != null)
            handler(this, new RepositoryEventArgs<T>(results));
    }

    // send results as message
    private void NotifyQueryCompleted(IEnumerable<T> results)
    {
        Messenger.Default.Send(new GenericMessage<IEnumerable<T>>(this, results));
    }
}

// event args holding queried items
public class RepositoryEventArgs<T> : EventArgs
{
    public RepositoryEventArgs(IEnumerable<T> result)
    {
        Results = result;
    }

    public IEnumerable<T> Results { get; set; }
}

因此,轮询器将查询给定时间间隔之间的数据,并通过event旧的然后更松散的耦合message(使用MVVMLight库NuGet依赖项)通知侦听器

在您中,ViewModel您将像这样使用它

public MainViewViewModel()
    : this(new RepositoryPoller<string>(
          TimeSpan.FromSeconds(0.5d), new SimpleRepository()))
{}

public MainViewViewModel(RepositoryPoller<string> repositoryPoller)
{
    RepositoryPoller = repositoryPoller;

    // If you prefer pub/sub...
    Messenger.Default.Register<GenericMessage<IEnumerable<string>>>(this, message =>
        {
            var results = message.Content;
            Items = new ObservableCollection<string>(results);
        });

    // Or in case events feel more liek home
    RepositoryPoller.OnQueryComplete += (sender, args) =>
        {
            var results = args.Results;
            Items = new ObservableCollection<string>(results);
        };
    RepositoryPoller.Start();
}

public RepositoryPoller<string> RepositoryPoller { get; set; }

希望它能给您一些想法。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何从Firebase中的实时数据库获取数据

来自分类Dev

如何获取实时数据库中的特定密钥?

来自分类Dev

Laravel Helpers方法应如何从视图与数据库交互?

来自分类Dev

如何使用foreach从数据库表中获取数据-

来自分类Dev

如何从数据库获取数据到HTML表中?

来自分类Dev

如何在flutter中从Firebase实时数据库中获取数据?

来自分类Dev

如何从android中的firebase实时数据库中获取数据

来自分类Dev

如何获取firebase实时数据库的数据

来自分类Dev

Firebase 实时数据库,从键值对中获取数据

来自分类Dev

如何使用firebase实时数据库检查数据是否已经在html表中?

来自分类Dev

如何从Web中的Firebase实时数据库获取数据?

来自分类Dev

如何从Firebase实时数据库中获取数据并将其显示在微调器上

来自分类Dev

从数据库中的表获取数据

来自分类Dev

如何从数据库的多个表中获取公共列?

来自分类Dev

如何仅获取PostgreSQL中数据库的表名

来自分类Dev

如何从数据库表中获取哈希

来自分类Dev

如何从数据库的多个表中获取公共列?

来自分类Dev

如何从特定数据库中获取表的列名?

来自分类Dev

如何检查 firebase 实时数据库中的更改值并使它们显示在 html 表中?

来自分类Dev

如何从Firebase实时数据库获取最新记录

来自分类Dev

获取实时XML提要到MySQL数据库中?

来自分类Dev

在实时数据库中插入记录并获取密钥

来自分类Dev

Flutter:如何从Firebase实时数据库中获取新添加的记录?

来自分类Dev

如何从以下实时数据库结构中获取检索项?

来自分类Dev

如何从Firebase实时数据库中的.set()获取自动生成的ID?

来自分类Dev

如何获取Firebase实时数据库中添加的最后一项?

来自分类Dev

如何从Android中的Firebase实时数据库获取价值?

来自分类Dev

如何在 Firebase 实时数据库中获取子名称

来自分类Dev

如何从firebase存储获取imageUrl以存储在firebase实时数据库中?

Related 相关文章

  1. 1

    如何从Firebase中的实时数据库获取数据

  2. 2

    如何获取实时数据库中的特定密钥?

  3. 3

    Laravel Helpers方法应如何从视图与数据库交互?

  4. 4

    如何使用foreach从数据库表中获取数据-

  5. 5

    如何从数据库获取数据到HTML表中?

  6. 6

    如何在flutter中从Firebase实时数据库中获取数据?

  7. 7

    如何从android中的firebase实时数据库中获取数据

  8. 8

    如何获取firebase实时数据库的数据

  9. 9

    Firebase 实时数据库,从键值对中获取数据

  10. 10

    如何使用firebase实时数据库检查数据是否已经在html表中?

  11. 11

    如何从Web中的Firebase实时数据库获取数据?

  12. 12

    如何从Firebase实时数据库中获取数据并将其显示在微调器上

  13. 13

    从数据库中的表获取数据

  14. 14

    如何从数据库的多个表中获取公共列?

  15. 15

    如何仅获取PostgreSQL中数据库的表名

  16. 16

    如何从数据库表中获取哈希

  17. 17

    如何从数据库的多个表中获取公共列?

  18. 18

    如何从特定数据库中获取表的列名?

  19. 19

    如何检查 firebase 实时数据库中的更改值并使它们显示在 html 表中?

  20. 20

    如何从Firebase实时数据库获取最新记录

  21. 21

    获取实时XML提要到MySQL数据库中?

  22. 22

    在实时数据库中插入记录并获取密钥

  23. 23

    Flutter:如何从Firebase实时数据库中获取新添加的记录?

  24. 24

    如何从以下实时数据库结构中获取检索项?

  25. 25

    如何从Firebase实时数据库中的.set()获取自动生成的ID?

  26. 26

    如何获取Firebase实时数据库中添加的最后一项?

  27. 27

    如何从Android中的Firebase实时数据库获取价值?

  28. 28

    如何在 Firebase 实时数据库中获取子名称

  29. 29

    如何从firebase存储获取imageUrl以存储在firebase实时数据库中?

热门标签

归档