更新项目配置,新增设备同步模块,优化WebSocket和Swagger配置,增强SCADA系统的免登录接口,支持数据字典项和登录日志的免登录查询与记录。调整Java编译设置,确保更好的开发体验。
This commit is contained in:
117
yy-admin-master/YY.Admin.Core/Extension/DataGridExtensions.cs
Normal file
117
yy-admin-master/YY.Admin.Core/Extension/DataGridExtensions.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
|
||||
namespace YY.Admin.Core.Extension
|
||||
{
|
||||
/// <summary>
|
||||
/// DataGrid扩展方法
|
||||
/// </summary>
|
||||
public static class DataGridExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 动态生成列
|
||||
/// </summary>
|
||||
/// <param name="dataGrid">DataGrid控件实例</param>
|
||||
/// <param name="index">列插入位置</param>
|
||||
/// <param name="data">数据源</param>
|
||||
/// <param name="operationKey">操作列资源</param>
|
||||
/// <param name="operationWidth">操作列宽度</param>
|
||||
public static void GenerateColumns(this DataGrid dataGrid, int index, object data, string operationKey, DataGridLength operationWidth)
|
||||
{
|
||||
IList<BindDescriptionAttribute> list = GetColumns(data);
|
||||
//Window win = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
|
||||
//Page page = win.GetChildObject<Page>("page");
|
||||
//if (page == null) throw new Exception("未獲取到當前窗口名稱爲page的(Page)頁面對象,原因:沒有爲Page設置Name,且名稱必須爲【page】!");
|
||||
|
||||
Page page = GetParentObject<Page>(dataGrid, "page");
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
switch (list[i].ShowAs)
|
||||
{
|
||||
case ShowScheme.普通文本:
|
||||
dataGrid.Columns.Insert(i + index, new DataGridTextColumn
|
||||
{
|
||||
Header = list[i].HeaderName,
|
||||
Binding = new Binding(list[i].PropertyName),
|
||||
Width = list[i].Width
|
||||
});
|
||||
break;
|
||||
case ShowScheme.自定义:
|
||||
if (page.FindResource(list[i].ResourceKey) != null)
|
||||
{
|
||||
DataGridTemplateColumn val = new DataGridTemplateColumn();
|
||||
val.Header = list[i].HeaderName;
|
||||
val.Width = list[i].Width;
|
||||
val.CellTemplate = page.FindResource(list[i].ResourceKey) as DataTemplate;
|
||||
dataGrid.Columns.Insert(i + index, val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(operationKey) && page != null)
|
||||
{
|
||||
var resource = page.FindResource(operationKey);
|
||||
if (resource != null)
|
||||
{
|
||||
|
||||
var col = new DataGridTemplateColumn() { Header = "操作", Width = operationWidth };
|
||||
col.CellTemplate = resource as DataTemplate;
|
||||
dataGrid.Columns.Add(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据源对象到列的映射关系
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private static IList<BindDescriptionAttribute> GetColumns(object data)
|
||||
{
|
||||
List<BindDescriptionAttribute> list = new List<BindDescriptionAttribute>();
|
||||
var pros = data.GetType().GenericTypeArguments[0].GetProperties();
|
||||
foreach (var item in pros)
|
||||
{
|
||||
var a = item.GetCustomAttribute<BindDescriptionAttribute>();
|
||||
if (a != null) { a.PropertyName = item.Name; list.Add(a); }
|
||||
}
|
||||
return list.OrderBy(x => x.DisplayIndex).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找父级控件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetParentObject<T>(DependencyObject obj, string name) where T : FrameworkElement
|
||||
{
|
||||
DependencyObject parent = VisualTreeHelper.GetParent(obj);
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent is T && (((T)parent).Name == name | string.IsNullOrEmpty(name)))
|
||||
{
|
||||
return (T)parent;
|
||||
}
|
||||
|
||||
parent = VisualTreeHelper.GetParent(parent);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
yy-admin-master/YY.Admin.Core/Extension/EnumExtensions.cs
Normal file
14
yy-admin-master/YY.Admin.Core/Extension/EnumExtensions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace YY.Admin.Core.Extension
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static string GetDescription(this Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
var attribute = field?.GetCustomAttribute<DescriptionAttribute>();
|
||||
return attribute?.Description ?? value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
yy-admin-master/YY.Admin.Core/Extension/EnumerableExtension.cs
Normal file
114
yy-admin-master/YY.Admin.Core/Extension/EnumerableExtension.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YY.Admin.Core.Extension;
|
||||
|
||||
namespace YY.Admin.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据集合拓展类
|
||||
/// </summary>
|
||||
public static class EnumerableExtension
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, PropertyInfo> PropertyCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 查询有父子关系的数据集
|
||||
/// </summary>
|
||||
/// <param name="list">数据集</param>
|
||||
/// <param name="idExpression">主键ID字段</param>
|
||||
/// <param name="parentIdExpression">父级字段</param>
|
||||
/// <param name="topParentIdValue">顶级节点父级字段值</param>
|
||||
/// <param name="isContainOneself">是否包含顶级节点本身</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> ToChildList<T, P>(this IEnumerable<T> list,
|
||||
Expression<Func<T, P>> idExpression,
|
||||
Expression<Func<T, P>> parentIdExpression,
|
||||
object topParentIdValue,
|
||||
bool isContainOneself = true)
|
||||
{
|
||||
if (list == null || !list.Any()) return Enumerable.Empty<T>();
|
||||
|
||||
var propId = GetPropertyInfo(idExpression);
|
||||
var propParentId = GetPropertyInfo(parentIdExpression);
|
||||
|
||||
// 查找所有顶级节点
|
||||
var topNodes = list.Where(item => Equals(propId.GetValue(item), topParentIdValue)).ToList();
|
||||
|
||||
return TraverseHierarchy(list, propId, propParentId, topNodes, isContainOneself);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询有父子关系的数据集
|
||||
/// </summary>
|
||||
/// <param name="list">数据集</param>
|
||||
/// <param name="idExpression">主键ID字段</param>
|
||||
/// <param name="parentIdExpression">父级字段</param>
|
||||
/// <param name="topLevelPredicate">顶级节点的选择条件</param>
|
||||
/// <param name="isContainOneself">是否包含顶级节点本身</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> ToChildList<T, P>(this IEnumerable<T> list,
|
||||
Expression<Func<T, P>> idExpression,
|
||||
Expression<Func<T, P>> parentIdExpression,
|
||||
Expression<Func<T, bool>> topLevelPredicate,
|
||||
bool isContainOneself = true)
|
||||
{
|
||||
if (list == null || !list.Any()) return Enumerable.Empty<T>();
|
||||
|
||||
// 获取顶级节点
|
||||
var topNodes = list.Where(topLevelPredicate.Compile()).ToList();
|
||||
|
||||
if (!topNodes.Any()) return Enumerable.Empty<T>();
|
||||
|
||||
var idPropertyInfo = GetPropertyInfo(idExpression);
|
||||
var parentPropertyInfo = GetPropertyInfo(parentIdExpression);
|
||||
|
||||
return TraverseHierarchy(list, idPropertyInfo, parentPropertyInfo, topNodes, isContainOneself);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 辅助方法,从表达式中提取属性信息并使用临时缓存
|
||||
/// </summary>
|
||||
private static PropertyInfo GetPropertyInfo<T, P>(Expression<Func<T, P>> expression)
|
||||
{
|
||||
// 使用 ConcurrentDictionary 确保线程安全
|
||||
return PropertyCache.GetOrAdd(typeof(T).FullName + "." + ((MemberExpression)expression.Body).Member.Name, k =>
|
||||
{
|
||||
if (expression.Body is UnaryExpression { Operand: MemberExpression member }) return (PropertyInfo)member.Member;
|
||||
if (expression.Body is MemberExpression memberExpression) return (PropertyInfo)memberExpression.Member;
|
||||
throw new Exception("表达式必须是一个属性访问: " + expression);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用队列遍历层级结构
|
||||
/// </summary>
|
||||
private static IEnumerable<T> TraverseHierarchy<T>(IEnumerable<T> list,
|
||||
PropertyInfo idPropertyInfo,
|
||||
PropertyInfo parentPropertyInfo,
|
||||
List<T> topNodes,
|
||||
bool isContainOneself)
|
||||
{
|
||||
var queue = new Queue<T>(topNodes);
|
||||
var result = new HashSet<T>(topNodes);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
var children = list.Where(item => Equals(parentPropertyInfo.GetValue(item), idPropertyInfo.GetValue(currentNode))).ToList();
|
||||
children.Where(child => result.Add(child)).ForEach(child => queue.Enqueue(child));
|
||||
}
|
||||
if (isContainOneself) return result;
|
||||
|
||||
// 如果不需要包含顶级节点本身,则移除它们
|
||||
topNodes.ForEach(e => result.Remove(e));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
yy-admin-master/YY.Admin.Core/Extension/ListExtensions.cs
Normal file
49
yy-admin-master/YY.Admin.Core/Extension/ListExtensions.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace YY.Admin.Core.Extension
|
||||
{
|
||||
public static class ListExtensions
|
||||
{
|
||||
public static async Task ForEachAsync<T>(this List<T> list, Func<T, Task> func)
|
||||
{
|
||||
foreach (var value in list)
|
||||
{
|
||||
await func(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> action)
|
||||
{
|
||||
foreach (var value in source)
|
||||
{
|
||||
await action(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> consumer)
|
||||
{
|
||||
foreach (T item in enumerable)
|
||||
{
|
||||
consumer(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRange<T>(this IList<T> list, IEnumerable<T> items)
|
||||
{
|
||||
if (list is List<T> list2)
|
||||
{
|
||||
list2.AddRange(items);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (T item in items)
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
221
yy-admin-master/YY.Admin.Core/Extension/ObjectExtension.cs
Normal file
221
yy-admin-master/YY.Admin.Core/Extension/ObjectExtension.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using NewLife.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace YY.Admin.Core.Extension
|
||||
{
|
||||
public static partial class ObjectExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型属性列表映射表
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertyCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 判断类型是否实现某个泛型
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="generic">泛型类型</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool HasImplementedRawGeneric(this Type type, Type generic)
|
||||
{
|
||||
// 检查接口类型
|
||||
var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
|
||||
if (isTheRawGenericType) return true;
|
||||
|
||||
// 检查类型
|
||||
while (type != null && type != typeof(object))
|
||||
{
|
||||
isTheRawGenericType = IsTheRawGenericType(type);
|
||||
if (isTheRawGenericType) return true;
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
// 判断逻辑
|
||||
bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
|
||||
}
|
||||
/// <summary>
|
||||
/// 判断类型是否为Nullable类型
|
||||
/// </summary>
|
||||
/// <param name="type"> 要处理的类型 </param>
|
||||
/// <returns> 是返回True,不是返回False </returns>
|
||||
public static bool IsNullableType(this Type type)
|
||||
{
|
||||
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||
}
|
||||
/// <summary>
|
||||
/// 通过类型转换器获取Nullable类型的基础类型
|
||||
/// </summary>
|
||||
/// <param name="type"> 要处理的类型对象 </param>
|
||||
/// <returns> </returns>
|
||||
public static Type GetUnNullableType(this Type type)
|
||||
{
|
||||
if (IsNullableType(type))
|
||||
{
|
||||
NullableConverter nullableConverter = new NullableConverter(type);
|
||||
return nullableConverter.UnderlyingType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
#region 公共方法
|
||||
/// <summary>
|
||||
/// 从类型成员获取指定Attribute特性
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Attribute特性类型</typeparam>
|
||||
/// <param name="memberInfo">类型类型成员</param>
|
||||
/// <param name="inherit">是否从继承中查找</param>
|
||||
/// <returns>存在返回第一个,不存在返回null</returns>
|
||||
public static T GetAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
|
||||
{
|
||||
var attributes = memberInfo.GetCustomAttributes(typeof(T), inherit);
|
||||
return attributes.FirstOrDefault() as T;
|
||||
}
|
||||
/// <summary>
|
||||
/// 把对象类型转换为指定类型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="conversionType"></param>
|
||||
/// <returns></returns>
|
||||
public static object CastTo(this object value, Type conversionType)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (conversionType.IsNullableType())
|
||||
{
|
||||
conversionType = conversionType.GetUnNullableType();
|
||||
}
|
||||
if (conversionType.IsEnum)
|
||||
{
|
||||
return Enum.Parse(conversionType, value.ToString());
|
||||
}
|
||||
if (conversionType == typeof(Guid))
|
||||
{
|
||||
return Guid.Parse(value.ToString());
|
||||
}
|
||||
|
||||
if (conversionType == typeof(string)) return value.ToString();
|
||||
if (value.GetType() == typeof(JsonElement)) return Convert.ChangeType(value?.ToString(), conversionType);
|
||||
return Convert.ChangeType(value, conversionType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把对象类型转化为指定类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T"> 动态类型 </typeparam>
|
||||
/// <param name="value"> 要转化的源对象 </param>
|
||||
/// <returns> 转化后的指定类型的对象,转化失败引发异常。 </returns>
|
||||
public static T CastTo<T>(this object value)
|
||||
{
|
||||
if (value == null || default(T) == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
if (value.GetType() == typeof(T))
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
object result = CastTo(value, typeof(T));
|
||||
return (T)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把对象类型转化为指定类型,转化失败时返回指定的默认值
|
||||
/// </summary>
|
||||
/// <typeparam name="T"> 动态类型 </typeparam>
|
||||
/// <param name="value"> 要转化的源对象 </param>
|
||||
/// <param name="defaultValue"> 转化失败返回的指定默认值 </param>
|
||||
/// <returns> 转化后的指定类型对象,转化失败时返回指定的默认值 </returns>
|
||||
public static T CastTo<T>(this object value, T defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CastTo<T>(value);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前值是否介于指定范围内
|
||||
/// </summary>
|
||||
/// <typeparam name="T"> 动态类型 </typeparam>
|
||||
/// <param name="value"> 动态类型对象 </param>
|
||||
/// <param name="start"> 范围起点 </param>
|
||||
/// <param name="end"> 范围终点 </param>
|
||||
/// <param name="leftEqual"> 是否可等于上限(默认等于) </param>
|
||||
/// <param name="rightEqual"> 是否可等于下限(默认等于) </param>
|
||||
/// <returns> 是否介于 </returns>
|
||||
public static bool IsBetween<T>(this IComparable<T> value, T start, T end, bool leftEqual = true, bool rightEqual = true) where T : IComparable
|
||||
{
|
||||
bool flag = leftEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0;
|
||||
return flag && (rightEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前值是否介于指定范围内
|
||||
/// </summary>
|
||||
/// <typeparam name="T"> 动态类型 </typeparam>
|
||||
/// <param name="value"> 动态类型对象 </param>
|
||||
/// <param name="min">范围小值</param>
|
||||
/// <param name="max">范围大值</param>
|
||||
/// <param name="minEqual">是否可等于小值(默认等于)</param>
|
||||
/// <param name="maxEqual">是否可等于大值(默认等于)</param>
|
||||
public static bool IsInRange<T>(this IComparable<T> value, T min, T max, bool minEqual = true, bool maxEqual = true) where T : IComparable
|
||||
{
|
||||
bool flag = minEqual ? value.CompareTo(min) >= 0 : value.CompareTo(min) > 0;
|
||||
return flag && (maxEqual ? value.CompareTo(max) <= 0 : value.CompareTo(max) < 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否存在于
|
||||
/// </summary>
|
||||
public static bool IsIn<T>(this T value, params T[] source)
|
||||
{
|
||||
return source.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象[主要是匿名对象]转换为dynamic
|
||||
/// </summary>
|
||||
public static dynamic ToDynamic(this object value)
|
||||
{
|
||||
IDictionary<string, object> expando = new ExpandoObject();
|
||||
Type type = value.GetType();
|
||||
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(type);
|
||||
foreach (PropertyDescriptor property in properties)
|
||||
{
|
||||
var val = property.GetValue(value);
|
||||
if (property.PropertyType.FullName != null && property.PropertyType.FullName.StartsWith("<>f__AnonymousType"))
|
||||
{
|
||||
dynamic dval = val.ToDynamic();
|
||||
expando.Add(property.Name, dval);
|
||||
}
|
||||
else
|
||||
{
|
||||
expando.Add(property.Name, val);
|
||||
}
|
||||
}
|
||||
return (ExpandoObject)expando;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
46
yy-admin-master/YY.Admin.Core/Extension/WindowExtensions.cs
Normal file
46
yy-admin-master/YY.Admin.Core/Extension/WindowExtensions.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
|
||||
namespace YY.Admin.Core.Extension
|
||||
{
|
||||
/// <summary>
|
||||
/// 窗体的扩展类
|
||||
/// </summary>
|
||||
public static class WindowExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 查找子控件
|
||||
/// </summary>
|
||||
/// <typeparam name="T">子控件的类型</typeparam>
|
||||
/// <param name="obj">要找的是obj的子控件</param>
|
||||
/// <param name="name">想找的子控件的Name属性</param>
|
||||
/// <returns>目标子控件</returns>
|
||||
public static T GetChildObject<T>(this DependencyObject obj, string name) where T : FrameworkElement
|
||||
{
|
||||
DependencyObject child = null;
|
||||
T grandChild = null;
|
||||
|
||||
for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
|
||||
{
|
||||
child = VisualTreeHelper.GetChild(obj, i);
|
||||
|
||||
if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name)))
|
||||
{
|
||||
return (T)child;
|
||||
}
|
||||
else
|
||||
{
|
||||
grandChild = GetChildObject<T>(child, name);
|
||||
if (grandChild != null)
|
||||
return grandChild;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user