Как добиться "смешиваемости" при использовании DataServiceCollection в моей ViewModel

Я смотрю на использование конечных точек oData в моем клиенте Silverlight. Естественно, я делаю MVVM и хочу, чтобы проект был красивым и "смешиваемым" (то есть я должен иметь возможность чисто использовать статические данные вместо конечных точек oData в режиме разработки.)

Теперь к проблеме. Я хотел бы использовать DataServiceCollection в моих ViewModels, поскольку он позволяет создавать хорошие привязываемые коллекции, не беспокоясь о BeginExecute/EndExecute и т. Д.

Теперь давайте посмотрим на некоторый код. Моя модель интерфейса выглядит так:

public interface ITasksModel
{
    IQueryable<Task> Tasks { get; }
}

Реализация конечного пункта oData этого интерфейса:

public class TasksModel : ITasksModel
{
    Uri svcUri = new Uri("http://localhost:2404/Services/TasksDataService.svc");

    TaskModelContainer _container;

    public TasksModel()
    {
        _container = new TaskModelContainer(svcUri);
    }

    public IQueryable<Task> Tasks
    {
        get
        {
            return _container.TaskSet;
        }
    }
}

И "смешиваемая" реализация времени разработки:

public class DesignModeTasksModel : ITasksModel
{
    private List<Task> _taskCollection = new List<Task>();

    public DesignModeTasksModel()
    {
        _taskCollection.Add(new Task() { Id = 1, Title = "Task 1" });
        _taskCollection.Add(new Task() { Id = 2, Title = "Task 2" });
        _taskCollection.Add(new Task() { Id = 3, Title = "Task 3" });
    }

    public IQueryable<Task> Tasks
    {
        get {
            return _taskCollection.AsQueryable();
        }
    }
}

Однако, когда я пытаюсь использовать этот последний в моем конструкторе ViewModel:

    public TaskListViewModel(ITasksModel tasksModel)
    {
        _tasksModel = tasksModel;

        _tasks = new DataServiceCollection<Task>();
        _tasks.LoadAsync(_tasksModel.Tasks);
    }

Я получаю исключение:

Только типизированный объект DataServiceQuery может быть предоставлен при вызове метода LoadAsync для DataServiceCollection.

Прежде всего, если это так, почему бы не сделать тип входного параметра LoadAsync типом DataServiceQuery?

Во-вторых, каков "правильный" способ сделать то, что я пытаюсь достичь?

1 ответ

Решение

Причина, по которой LoadAsync требует DataServiceQuery, заключается в том, что просто IQueryable не определяет асинхронный способ выполнения запроса. Причина, по которой метод принимает тип IQueryable в качестве своего параметра, заключается в том, что пользователям не нужно явно приводить объект запроса к DataServiceQuery (делает код короче), и поскольку мы предполагаем, что пользователи попытаются выполнить свой код хотя бы один раз, они сразу увидеть ошибку (как вы сделали).

LoadAsync поддерживает только асинхронные операции, поэтому ему нужен DataServiceQuery. Если у вас уже есть результаты (без необходимости выполнения асинхронного запроса), вы можете вместо этого вызвать метод Load. Какой ответ на ваш второй вопрос. Вместо вызова LoadAsync как для времени разработки, так и для времени выполнения, вы можете использовать Load для времени разработки и LoadAsync для времени выполнения. Но из-за ограничений отслеживания вам может понадобиться создать DataServiceCollection другим способом.

Что-то вроде этого:

DataServiceCollection<Task> dsc;
DataServiceQuery<Task> dsq = _tasksModel as DataServiceQuery<Task>;
if (dsq != null)
{
    dsc = new DataServiceCollection<Task>();
    dsc.LoadAsync(dsq);
}
else
{
    dsc = new DataServiceCollection<Task>(myDataServiceContext);
    dsc.Load(_tasksModel);
    // Invoke the LoadAsyncCompleted handler here
}

Если вы передадите DataServiceContext конструктору до вызова Load, сущности будут отслеживаться (как в случае LoadAsync). Если вам это не нужно, вы можете вызвать конструктор, который принимает IEnumerable и TrackingMode, и отключить отслеживание для него.

Другие вопросы по тегам