所以现在我正在尝试设计一个新的租用程序,该程序授予对活动目录组的访问权限,生成包含其信息和位置的文档。
现在我正在使用枚举执行此操作,并使用switch语句设置ViewModel上的详细信息,如下所示:
case CaneRidgeSettings.Departments.SCSC:
Model.ScannerFolder = @"scan1\Supply Chain Service Center\" + Model.UserId;
Model.ExtensionRanges = "list station 8000 to-ext 8349";
Model.AdministrativeAssistant = Loader.SCSCAdminAssistant;
Model.DuoCode = "Franklin TN - 8175";
Model.PrinterSelectedIndex = (int)CaneRidgeSettings.PrinterGroups.Cane_Ridge_5th_Floor_West;
return await find.FindNextComputer("800SCSC");
我对此设计的问题是,如果我在此建筑物中添加更多部门,我必须手动更新此开关。所以我尝试了一些这样的东西,比如字典,但它似乎没有很好地绑定到一个组合框(即使在实现我自己的INotifyCollectionChanged时)。
所以我创建了一个包含这些信息的接口,为了简单和长度,我们只想说接口这样做:
public interface IDepartmentInfo
{
string DepartmentName { get; }
List<string> ActiveDirectoryGroups { get; }
string AdministrativeAssistant { get; }
string Floor { get; }
}
然后我创建了一个实现此接口的新类
public class SCSC : IDepartmentInfo
{
public string DepartmentName { get; } = "Shared Services";
public List<string> ActiveDirectoryGroups { get; } = new List<string>() {"Example_AD_GRP","Domain_Users"};
public string AdministrativeAssistant { get; } = "Lisa_Smith@outlook.com";
public string Floor { get; } = "5th Floor East";
public override string ToString() => DepartmentName;
}
然后,在我的主要建筑类中,我有一个可观察的集合,需要一个IDepartmentInfo并初始化这些部门
public class CaneRidgeBuilding : IBuilding
{
public ObservableCollection<IDepartmentInfo> Departments { get; set; } = new ObservableCollection<IDepartmentInfo>() {new SCSC(), new ARS()};
public override string ToString()
{
return "CaneRidge";
}
}
在我的视图模型上,我实现了一些属性,主要是BuildingSelectedIndex和DepartmentSelectedIndex。
我还有一个IDepartmentInfo属性,通知它何时被更改,因为它在我的UI上被数据绑定到多个标签。
public class MainWindowViewModel : BindableBase
{
public ObservableCollection<IBuilding> Buildings { get; set; } = new ObservableCollection<IBuilding>() { new CaneRidgeBuilding() };
private ObservableCollection<IDepartmentInfo> _departmentInfos = new ObservableCollection<IDepartmentInfo>();
public ObservableCollection<IDepartmentInfo> DepartmentInfos
{
get { return _departmentInfos; }
set { SetProperty(ref _departmentInfos, value); }
}
private int _buildingIndex = -1;
public int BuildingIndex
{
get { return _buildingIndex; }
set
{
SetProperty(ref _buildingIndex, value);
SetDepartments();
}
}
private void SetDepartments()
{
if (BuildingIndex != -1)
DepartmentInfos = Buildings[BuildingIndex].Departments;
}
private int _departmentIndex = -1;
public int DepartmentIndex
{
get { return _departmentIndex; }
set
{
SetProperty(ref _departmentIndex, value);
LoadDepartmentSettings();
}
}
private IDepartmentInfo _departmentInformation;
public IDepartmentInfo DepartmentInformation
{
get { return _departmentInformation; }
set { SetProperty(ref _departmentInformation, value); }
}
private void LoadDepartmentSettings()
{
if (DepartmentIndex != -1)
DepartmentInformation = DepartmentInfos[DepartmentIndex];
}
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainWindowViewModel()
{
}
}
它完全按我想要的方式工作,但是我现在遇到的问题是如何处理依赖注入?如果我有10个部门实现IDepartmentInfo,我怎么能将它传递给一个可观察的集合呢?
因为我介绍一个新建筑的那一刻,如果我告诉Unity解决所有IDepartmentInfos,那么即使它不属于CaneRidge,我也会得到每一个部门。
如果我将部门拆分到每个建筑物,那么我会遇到一些问题,我无法轻松地将部门加载到ViewModel中,因为它需要一个IDepartmentInfo集合。如果我将它限制在一种类型的集合中,那么它将无法工作。
我是不是太复杂了?
答案 0 :(得分:0)
我能够弄清楚如何注入不同的建筑物和部门,可能不是最好的方式
编辑:更新它以使用反射来减少维护
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterTypes(AllClasses.FromLoadedAssemblies()
.Where(type => typeof(IDepartment).IsAssignableFrom(type)), WithMappings.FromAllInterfaces, WithName.TypeName, WithLifetime.None);
ObservableCollection<IBuilding> Buildings = new ObservableCollection<IBuilding>()
{
Container.Resolve<Building1>(new ParameterOverride("departments",GetDepartmentCollection("Building1"))),
Container.Resolve<Building2>(new ParameterOverride("departments",GetDepartmentCollection("Building2")))
};
Container.RegisterInstance(typeof(ObservableCollection<IBuilding>), Buildings,
new ExternallyControlledLifetimeManager());
}
private ObservableCollection<IDepartment> GetDepartmentCollection(string buildingName)
{
var departments = new List<IDepartment>();
foreach (var registration in Container.Registrations.Where( s => s.MappedToType.Namespace.Contains(buildingName)))
{
departments.Add((IDepartment)Container.Resolve(registration.MappedToType));
}
return new ObservableCollection<IDepartment>(departments);
}
现在我可以完全消除枚举,并且可以在将来扩展而不会破坏任何代码或要求我更改任何内容。
答案 1 :(得分:0)
这是一个想法。
自定义属性
引入BuilingAttribute
,以便每个IDepartmentInfo
实施可以声明它所属的建筑物的Type
(如果一个部门可以属于多个建筑物,则允许多个,我知道它可以'吨)。
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class BuildingAttribute : Attribute
{
public Type BuildingType { get; private set; }
public BuildingAttribute(Type buildingType)
{
this.BuildingType = buildingType;
}
}
DepartmentInfo Collection Factory
一个知道如何为每个建筑DepartmentInfo
创建Type
集合的界面。
public interface IDepartmentInfoCollectionFactory
{
void RegisterDepartment<T>(Func<IDepartmentInfo> departmentCreator) where T : class, IBuilding;
ObservableCollection<IDepartmentInfo> GetDepartments<T>() where T : class, IBuilding;
}
实施(将注册为单身人士)。
public class DepartmentInfoCollectionFactory : IDepartmentInfoCollectionFactory
{
private readonly Dictionary<Type, List<Func<IDepartmentInfo>>> departmentCreators =
new Dictionary<Type, List<Func<IDepartmentInfo>>>();
void IDepartmentInfoCollectionFactory.RegisterDepartment<T>(Func<IDepartmentInfo> departmentCreator)
{
Type buildingType = typeof(T);
if (!this.departmentCreators.ContainsKey(buildingType))
this.departmentCreators.Add(buildingType, new List<Func<IDepartmentInfo>>());
if (!this.departmentCreators[buildingType].Contains(departmentCreator))
this.departmentCreators[buildingType].Add(departmentCreator);
}
ObservableCollection<IDepartmentInfo> IDepartmentInfoCollectionFactory.GetDepartments<T>()
{
Type buildingType = typeof(T);
if (!this.departmentCreators.ContainsKey(buildingType))
throw new InvalidOperationException(
string.Format("No departments have been registered for {0}.", buildingType.ToString()));
ObservableCollection<IDepartmentInfo> departmentInfos = new ObservableCollection<IDepartmentInfo>();
foreach(Func<IDepartmentInfo> creator in this.departmentCreators[buildingType])
{
departmentInfos.Add(creator());
}
return departmentInfos;
}
}
配置工厂,因此它知道如何创建IDepartmentInfo
集合。
protected override void ConfigureContainer()
{
Container.RegisterType<IDepartmentInfoCollectionFactory, DepartmentInfoCollectionFactory>(
new ContainerControlledLifetimeManager());
this.ConfigureDepartmentInfoCollectionFactory(Container.Resolve<IDepartmentInfoCollectionFactory>());
}
private void ConfigureDepartmentInfoCollectionFactory(IDepartmentInfoCollectionFactory factory)
{
// Types implementing IDepartmentInfo
var deptInfoTypes = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(t => typeof(IDepartmentInfo).IsAssignableFrom(t) && !t.IsInterface);
foreach(Type type in deptInfoTypes)
{
// Get collection of BuildingAttribute for the type
var buildingAttributes = type.GetCustomAttributes(typeof(BuildingAttribute), false)
.OfType<BuildingAttribute>();
if (buildingAttributes.Count() < 1)
throw new InvalidOperationException(
string.Format("The type {0} didn't declare BuildingArgument.", type.ToString()));
var buildingType = buildingAttributes.First().BuildingType;
if (buildingType == null || !buildingType.GetInterfaces().Contains(typeof(IBuilding)))
throw new InvalidOperationException(
string.Format("{0}: BuildingType is not an IBuilding.", type.ToString()));
var registerMethod = typeof(IDepartmentInfoCollectionFactory).GetMethod("RegisterDepartment")
.MakeGenericMethod(new Type[] { buildingType });
registerMethod.Invoke(factory, new object[]
{
new Func<IDepartmentInfo>(() => (IDepartmentInfo)Container.Resolve(type))
});
}
}
注入工厂。
public class FooBuilding : IBuilding
{
private IDepartmentInfoCollectionFactory factory;
private readonly ObservableCollection<IDepartmentInfo> departmentInfos;
public string Name { get; } = "FooBuilding";
public ObservableCollection<IDepartmentInfo> DepartmentInfos
{
get { return this.departmentInfos; }
}
public FooBuilding(IDepartmentInfoCollectionFactory factory)
{
this.factory = factory;
this.departmentInfos = factory.GetDepartments<FooBuilding>();
}
}
添加新部门
它不需要任何编辑,只需使用属性创建新类。
[Building(typeof(FooBuilding))]
public class BarDepartment : IDepartmentInfo
{
public string Name { get; } = "Bar department";
}