Всем привет. Суть проблемы. Есть пользователи с разными ролями, например: админ, модератор, юзер.
Я хочу иметь возможность ограничить то, что пользователи могут видеть на основе их роли. Т.е. на одной и той же View могут быть скрыты, заблокированы или же вовсе появится новые элементы управления, в зависимости от роли текущего пользователя.
Как такую задачу решить максимально гибко и правильно в контексте паттерна MVVM?
Ответ
На мой взгляд, имеет смысл создать иерархию моделей представления:
abstract class BaseRoleVm { ... }
class UserRoleVm : BaseRoleVm { ... }
class ModeratorRoleVm : BaseRoleVm { ... }
class AdminRoleVm : BaseRoleVm { ... }
Затем для каждой неабстрактной ViewModel создать по представлению (для переиспользования кода в представлении можно использовать стили, контролы, словари ресурсов).
В основном окне нужно будет завести свойство типа BaseRoleVm, которому будет присваиваться нужный наследник:
class MainVm
{
public BaseRoleVm Role { get; set; }
void UseAdminRole()
{
Role = new AdminRoleVm();
}
...
}
Такой подход позволит легко вносить изменения в представления/модели представления ролей, обеспечит их независимость друг от друга, предоставить возможность добавлять/удалять роли без вмешательства в логику работы основного окна.
UPD
Вот небольшой пример на основе словарей ресурсов:
Модели представления (лежат в папке ViewModels):
public abstract class BaseRoleVm : BaseVm
{
public abstract string Name { get; }
}
public class AdminRoleVm : BaseRoleVm
{
public override string Name
{
get { return "Админ"; }
}
}
public class UserRoleVm : BaseRoleVm
{
public override string Name
{
get { return "Юзер"; }
}
}
public class MainVm : BaseVm
{
public BaseRoleVm SelectedRole
{
get { return _selectedRole; }
set { SetField(ref _selectedRole, value); }
}
private BaseRoleVm _selectedRole;
public BaseRoleVm[] Roles { get; }
public MainVm()
{
// формировать список или создавать нужную модель представления можно через MEF или Reflection.
// тогда вы не будете зависеть от перечня ролей
Roles = new BaseRoleVm[]
{
new AdminRoleVm(),
new UserRoleVm(),
};
SelectedRole = Roles.FirstOrDefault();
}
}
Представления (лежат в папке Views)
// содержимое файла "AdminRole.xaml" (тип Resource Dictionary)
// содержимое файла "UserRole.xaml" (тип Resource Dictionary)
// главное окно
// содержимое файла "Main.xaml" (тип Window)
И простейший селектор шаблонов:
public class ViewModelTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null)
{
return null;
}
var itemType = item.GetType();
var resourceDictonary = new ResourceDictionary
{
Source = new Uri(string.Format(
"pack://application:,,,/{0};component/Views/{1}.xaml",
itemType.Assembly.FullName,
itemType.Name.Replace("Vm", string.Empty)))
};
return resourceDictonary
.Values
.OfType
На уровне представления роли никак не связаны между собой. ContentControl использует написанный ViewModelTemplateSelector для поисков нужных шаблонов. Происходит примерно следующее:
У ContentControl меняется Content (сработало PropertyChanged)
ContentControl вызывает у ViewModelTemplateSelector метод SelectTemplate и передает туда Content в качестве item
ViewModelTemplateSelector находит файл с представлением на основе имени типа и достает оттуда DataTemplate
ContentControl отображает Content с использованием найденного DataTemplate
Комментариев нет:
Отправить комментарий