private LinkData CreateLinkDataForSubProperties(Type type, object context, string contextInfoName, string viewElementInfoName, List <PropertyInfo> propertyPath, LinkRule rule) { foreach (PropertyInfo pInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (!pInfo.PropertyType.IsClass || pInfo.PropertyType == typeof(string)) { continue; } object subContext; Type subType; if (typeof(IEnumerable).IsAssignableFrom(pInfo.PropertyType)) { // if the type is a ienurable type then set the context to null because then the linker should be only informed // about the found members in the generic used class subContext = null; subType = pInfo.PropertyType.GetGenericArguments().First(); } else if (pInfo.GetIndexParameters().Length <= 0) { subContext = pInfo.GetValue(context); subType = pInfo.PropertyType; } else { subContext = null; subType = pInfo.PropertyType; } LinkData data = CreateLinkData(null, rule, subType, subContext, viewElementInfoName, propertyPath, null); // if a match found in the sub class then return the link data. if (data != null) { propertyPath.Add(pInfo); return(data); } } return(null); }
private LinkData CreateLinkData(string controlName, LinkRule rule, Type type, object context, string viewElementInfoName, List <PropertyInfo> propertyPath, object view) { string[] nameParts = RuleProvider.GetNameSeparatorFunc()?.Invoke(controlName ?? string.Empty) ?? null; if (nameParts == null || nameParts.Length == 1) { if (string.IsNullOrEmpty(controlName)) { return(null); } MemberInfo info = type.GetMember(rule.GetLinkInfoName(controlName), BindingFlags.Instance | BindingFlags.Public).FirstOrDefault(); // if there was already a match found then create a LinkData and return it if (info != null) { return(new LinkData(viewElementInfoName, info, context, propertyPath)); } propertyPath = new List <PropertyInfo>(); // if no match found then search within all properties of the passed context which are a class itself (except enumerables) LinkData data = CreateLinkDataForSubProperties(type, context, rule.GetLinkInfoName(controlName), viewElementInfoName, propertyPath, rule); if (data != null) { data.PropertyPath = data.PropertyPath?.Reverse(); } return(data); } else { propertyPath = new List <PropertyInfo>(); Type currentType = type; object lastControl = null; for (int i = 0; i < nameParts.Length; i++) { // if the last of the name parts is reached then try to create the link data with the collected infos. if (i == nameParts.Length - 1) { return(CreateLinkData(nameParts[i], rule, currentType, context, viewElementInfoName, propertyPath, view)); } // if no last control is set then first try to find the control which is defined in this name part. if (lastControl == null) { EnumerateFields(view.GetType(), info => { if (info.Name == nameParts[i]) { lastControl = info.GetValue(view); } }); } else { // get the context property name for further search based on the last control and the current name part which must define the property of the control // to get the context property name for further search. string contextPropertyName = RuleProvider.GetContextPropertyNameForTypeAndProperty(lastControl.GetType(), nameParts[i], nameParts[i - 1]); // get the property info for the context property and add it to the property path. Just assume that the property is found. It's ok if a exception occurs // if the property could not be found because of e.g. typos. PropertyInfo pInfo = currentType.GetProperty(contextPropertyName, BindingFlags.Instance | BindingFlags.Public); propertyPath.Add(pInfo); // set the current type for the next search or link creation! currentType = pInfo.PropertyType; lastControl = null; } } } return(null); }