Как добиться "смешиваемости" при использовании 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, и отключить отслеживание для него.