У меня есть классы и интерфейсы:
public interface IEntity
{
int ID { get; set; }
}
public class Entity : IEntity
{
public int ID { get; set; }
}
public interface IEntityListViewModel
{
RangeObservableCollection
void LoadItems();
}
Теперь мне нужен такой класс:
public abstract class EntityListViewModel
public EntityListViewModel()
{
Items = new RangeObservableCollection
protected abstract List
public void LoadItems()
{
var lst = GetEntities();
Items.ReplaceRange(lst);
}
}
Естественно, компилятор требует реализации RangeObservableCollection.Items
Я бы мог сделать так:
public interface IEntityListViewModel
void LoadItems();
}
Но у меня есть еще один класс:
public abstract class UserControlBase : UserControl
{
public IEntityListViewModel VM { get; set; }
public virtual void Page_Loaded(object sender, RoutedEventArgs e)
{
VM.LoadItems();
}
}
А дальше уже конкретные UserControl'ы наследуются от UserControlBase. Для чего это мне? В UserControl'ах куча повторяющегося кода (в основном привязки событий ViewModel). Поэтому это все я хочу сделать в UserControlBase. Я бы мог объявить в UserControlBase так:
public IEntityListViewModel
но тогда мне T нужно поднимать в UserControlBase, а это как-то криво.
Как мне наследовать EntityListViewModel от обычного IEntityListViewModel? Или есть какое-то другое решение?
UPD 1:
Явно реализовал, как посоветовали в комментариях:
public abstract class EntityListViewModel
public EntityListViewModel()
{
Items = new RangeObservableCollection
protected abstract List
public void LoadItems()
{
var lst = GetEntities();
Items.ReplaceRange(lst);
}
}
Но теперь во View вызов VM.Items обращается к IEntityListViewModel.Items
Ответ
В текущем виде самым простым для вас было бы действительно объявить UserControlBase обобщенным. Если же этот способ вам по какой-то причине не подойдет - надо выносить хранение из базового класса в наследники.
В вашем случае, если базовый класс подписывается на события - ему нужен интерфейс INotifyCollectionChanged. Его и надо запрашивать у наследника:
public abstract class UserControlBase : UserControl
{
protected abstract INotifyCollectionChanged AbstractItems { get; }
}
public class FooListControl : UserControlBase
{
public IEntityListViewModel
protected virtual INotifyCollectionChanged AbstractItems => VM.Items;
}
Если при таком подходе в базовом классе оказывается слишком много полей - надо выделять в интерфейсе ковариантную часть.
Например, для ваш интерфейс IEntityListViewModel можно разбить следующим образом:
public interface IEntityListViewModel
public interface IEntityListViewModelOut
void LoadItems();
}
Реализовать такой "усложненный" интерфейс не сильно сложнее чем обычный:
public class EntityListViewModel
IEntityListViewModelOut
После этого, ковариантную часть можно "пробросить" в базовый класс через абстрактное свойство:
public abstract class UserControlBase : UserControl
{
protected abstract IEntityListViewModelOut
public class FooListControl : UserControlBase
{
public IEntityListViewModel
protected virtual IEntityListViewModelOut
Комментариев нет:
Отправить комментарий