private List <string> BuildBinderHost(BuildStackTrace trace, PBinderHost rootHost) { var parameterLines = new List <string>(); // 연결된 파라미터 바인더 가져옴 foreach (var expression in rootHost .GetExpressions() .Where(e => e.Direction == BindDirection.Input && e.Input.BindOption == BindOptions.Parameter)) { var host = expression.Output.Host as PBinderHost; // 파라미터 역전파로 트리거에 도달하는 경우 // 무조건 sender를 가져옴 if (host is PTrigger) { DXMappingResult result = buildImpl(trace, host, "{Target}"); parameterLines.Add(result.Source); } else if (host.HasAttribute <TAttribute>()) { var attr = host.GetAttribute <TAttribute>(); DXMappingResult result = buildImpl(trace, host, attr.MappingCode); parameterLines.Add(result.Source); } } return(parameterLines); }
private bool BuildParam(BuildStackTrace trace, DXMappingResult result, DXToken token, object obj, StringBuilder sourceBuilder) { if (obj is PFunction func) { string paramName = token.Parameters[0]; NamedParameterInfo pi = func.ParameterInfos.FirstOrDefault(p => p.Name == paramName); if (pi != null) { int idx = Array.IndexOf(func.ParameterInfos, pi); IBinder[] binders = func.Items.Find(BindOptions.Parameter).ToArray(); if (binders.Length > idx) { string source = BuildBinder(trace, result, binders[idx] as PBinder); sourceBuilder.Replace( token.OriginalSource, source); } } } return(false); }
private bool BuildTarget(BuildStackTrace trace, DXMappingResult result, DXToken token, object obj, StringBuilder source) { bool isMultiline = false; var targetVisuals = new List <PVisual>(); if (obj is PTrigger trigger) { source.Replace( token.OriginalSource, "sender"); return(true); } if (obj is PLayoutBinderHost host) { targetVisuals.Add(host.LogicalParent); } if (obj is PSelector selector) { targetVisuals.Clear(); targetVisuals.SafeAdd(selector.TargetVisual); } if (obj is PDataBinding binding) { if (trace.GetFrame(0).Source.GetType() == typeof(PSetter)) { source.Clear(); source.Append("DXDatastore"); return(true); } } if (obj is PTargetable targetable) { // 연결됨 if (targetable.TargetBinder.Items.Count > 0) { string line = source.ToString(); IBinderHost[] hosts = targetable.TargetBinder.Items .Select(item => item.Host) .ToArray(); isMultiline = true; source.Clear(); for (int i = 0; i < hosts.Length; i++) { string tempLine = line; PVisual targetVisual = null; // 레이아웃에서 직접 연결 if (hosts[i] is PLayoutBinderHost targetLayoutHost) { targetVisual = targetLayoutHost.LogicalParent; } // 선택기로 가져옴 if (hosts[i] is PSelector targetSelector) { targetVisual = targetSelector.TargetVisual; } // Target을 해결하지 못한경우는 무조건 이벤트 sender if (targetVisual == null) { tempLine = tempLine.Replace(token.OriginalSource, "sender"); } else { // {Target} -> {Target:i} tempLine = tempLine.Replace(token.OriginalSource, $"{{{token.Token}:{i}}}"); targetVisuals.Add(targetVisual); } if (i > 0) { source.AppendLine(); } source.Append(tempLine); } } } for (int i = 0; i < targetVisuals.Count; i++) { if (this.NameContainer.ContainsValue(targetVisuals[i])) { string name = this.NameContainer[targetVisuals[i]].Trim('_'); string tokenSource = token.OriginalSource; if (isMultiline) { tokenSource = $"{{{token.Token}:{i}}}"; } source.Replace( tokenSource, name); } } if (targetVisuals.Count > 0) { return(true); } return(false); }
private DXMappingResult buildImpl(BuildStackTrace trace, object obj, string source) { // trace capture trace.Capture(obj, source); var result = new DXMappingResult(); var sourceBuilder = new StringBuilder(source); // 이벤트 핸들러 연결 코드 및 콜백 이름 생성 if (obj is PTrigger trigger && source.Contains("{EventName}")) { var eventBuilder = new StringBuilder(); string eventName = this.MappingProvider.GetEventName(trigger); source = source.Replace("{EventName}", eventName); foreach (var item in trigger .GetExpressions() .Where(e => e.Direction == BindDirection.Input && e.Input.BindOption == BindOptions.Input)) { var targetHost = item.Output.Host as PLayoutBinderHost; var hostResult = buildImpl(trace, targetHost, source); eventBuilder.AppendLine(hostResult.Source); foreach (DXToken errorToken in hostResult.Errors) { result.AddErrorToken(errorToken); } foreach (DXToken resolvedToken in hostResult.Resolved) { result.AddErrorToken(resolvedToken); } } sourceBuilder = new StringBuilder(eventBuilder.ToString()); } // 토큰 처리 foreach (DXToken token in DXToken.Parse(sourceBuilder.ToString())) { if (!IsSupportToken(token)) { result.Errors.Add(token); continue; } bool tokenResult = false; switch (token.Token) { case "Property": tokenResult = this.BuildProperty(trace, result, token, obj, sourceBuilder); break; case "Function": tokenResult = this.BuildFunction(trace, result, token, obj, sourceBuilder); break; case "Target": tokenResult = this.BuildTarget(trace, result, token, obj, sourceBuilder); break; case "Param": tokenResult = this.BuildParam(trace, result, token, obj, sourceBuilder); break; } if (tokenResult) { result.AddResolvedToken(token); } else { result.AddErrorToken(token); if (token.IsSafe) { sourceBuilder.Replace(token.OriginalSource, ""); } } } result.Source = sourceBuilder.ToString(); return(result); }
public DXMappingResult Build(object obj, string source) { var trace = new BuildStackTrace(); return(buildImpl(trace, obj, source)); }
private bool BuildFunction(BuildStackTrace trace, DXMappingResult result, DXToken token, object obj, StringBuilder source) { Type objType = obj.GetType(); if (!token.HasParameter) { return(false); } // 클래스가 아닌경우 if (!obj.GetType().IsClass) { return(false); } if (token.HasReturn) { // * 함수 정보에서 가져옴 if (obj is PFunction pFunc) { if (pFunc.Items.Find(BindOptions.Parameter).Count() != pFunc.ParameterInfos.Length) { return(false); } if (pFunc.FunctionInfo.RuntimeMethodInfo.HasAttribute <TAttribute>()) { var tAttr = pFunc.FunctionInfo.RuntimeMethodInfo.GetAttribute <TAttribute>(); var tResult = buildImpl(trace, pFunc, tAttr.MappingCode); source.Replace( token.OriginalSource, $"({tResult.Source})"); } else { List <string> lines = this.BuildBinderHost(trace, pFunc); source.Replace( token.OriginalSource, this.MappingProvider.GetFunctionLine(pFunc, lines.ToArray())); } foreach (DXToken iToken in DXToken.Parse(source.ToString())) { result.AddErrorToken(iToken); } } } else { // * 함수 호출 및 반환값으로 치환 // 토큰 파라미터로 메서드 가져옴 MethodInfo mi = objType.GetMethod(token.Parameters.FirstOrDefault()); int depth = token.SubParameters.GetInt("depth"); // 지원하지 않는 메서드 if (!IsSupportMethod(mi)) { return(false); } if (mi == null || obj == null) { } // 메서드 호출 string code = (string)mi.Invoke(obj, new object[] { depth }); source.Replace( token.OriginalSource, code); return(true); } return(false); }
private bool BuildProperty(BuildStackTrace trace, DXMappingResult result, DXToken token, object obj, StringBuilder source) { try { Type objType = obj.GetType(); if (!token.HasParameter) { return(false); } // 클래스가 아닌경우 if (!obj.GetType().IsClass) { return(false); } // 인라인 파라미터 bool inline = token.SubParameters.GetBool("inline"); // 속성에서 실제값을 가져옴 var propertySolve = SolvePropertyValue(obj, token.Parameters.FirstOrDefault()); if (!propertySolve.Solved) { return(false); } string valueLine = null; // 속성값이 바인더인 경우 if (propertySolve.Result is PBinder binder) { valueLine = this.BuildBinder(trace, result, binder); } else if (IsArrayType(propertySolve.Result?.GetType())) { var sb = new StringBuilder(); var list = propertySolve.Result as IList; if (list.Count > 0) { foreach (object item in list) { if (sb.Length > 0) { sb.Append(", "); } if (item is PComponent) { var attr = item.GetAttribute <TAttribute>(); sb.Append(buildImpl(trace, item, attr.MappingCode).Source); } else { sb.Append(item); } } valueLine = sb.ToString(); } } else if (propertySolve.Result is DependencyProperty prop) { PropertyInfo targetPi = prop.OwnerType.GetProperty(prop.Name); valueLine = this.MappingProvider.GetValueLine(targetPi, inline); } // 객체 참조인 경우 else if (propertySolve.Result is Guid guid) { foreach (var model in this.SharedConatiner.Values) { if (model is PObject pObj) { if (guid == pObj.Guid) { valueLine = this.MappingProvider.GetValueLine(this.SharedConatiner[pObj], inline); break; } } } } else { valueLine = this.MappingProvider.GetValueLine(propertySolve.Result, inline); } if (propertySolve.Result == null && obj is PTargetable targetable && targetable.TargetType == typeof(PBucket)) { // A.B = C; // A.B(~~, C); if (targetable.TargetBinder.Items.Count > 0 && targetable.TargetBinder.Items[0].Host is PDataBinding) { var bucket = targetable.TargetBinder.Items[0].Host as PDataBinding; source.Replace(" = ", $"(\"{bucket.DataPath}\", "); source.Replace(";", ");"); valueLine = "Update"; } } if (valueLine != null) { // source 토큰 치환 foreach (DXToken innerToken in DXToken.Parse(valueLine)) { source.Replace(innerToken.OriginalSource, ""); } source.Replace( token.OriginalSource, valueLine); } } catch (Exception e) { } return(true); }
private string BuildBinder(BuildStackTrace trace, DXMappingResult result, PBinder binder) { // 직접 입력 값 if (binder.IsDirectValue) { object value = binder.DirectValue; if (value is string vStr) { Match match = Regex.Match(vStr, "(?<=^\")(\\d+\\.\\d+|\\d+)(?=\"$)"); if (match.Success) { return(vStr); } else if (double.TryParse(vStr, out double v)) { return(v.ToString()); } else if (vStr == "\"\"") { return(vStr); } } return(MappingProvider.GetValueLine(value, true)); } // 연결된 파라미터가 없음 if (binder.Items.Count == 0) { return(null); } // 연결된 파라미터의 부모 (컴포넌트) var previousHost = binder.Items[0].Host as PBinderHost; string mappingCode = previousHost.GetAttribute <TAttribute>().MappingCode; if (binder.HasAttribute <TAttribute>()) { mappingCode = binder.GetAttribute <TAttribute>().MappingCode; } // 코드 매핑 var r = buildImpl(trace, previousHost, mappingCode); string valueLine = r.Source; foreach (var token in r.Errors) { result.AddErrorToken(token); } foreach (var token in r.Resolved) { result.AddResolvedToken(token); } // 대입 값인 경우 대상 속성에 따라 캐스팅이 필요함 if ((binder as PParameterBinder).Host is PSetter setter) { if (setter.ValueBinder.Equals(binder)) { Type valueType = previousHost.GetType(); if (previousHost is PFunction prevFunc) { valueType = prevFunc.FunctionInfo.ReturnType; } if (previousHost is PGetter prevGetter) { valueType = prevGetter.Property.PropertyType; } if (previousHost is PLayoutBinderHost prevLayout) { valueType = prevLayout.LogicalParent.GetType(); } if (previousHost is PSelector prevSelector) { valueType = prevSelector.TargetVisual.GetType(); } if (setter.Property == null && previousHost is PStructure structure) { if (structure.Fields.Count > 0) { var builder = new StringBuilder(); var attr = typeof(PDataField).GetAttribute <TAttribute>(); PDataField[] fields = structure.Fields .Where(f => f.ValueBinder.Items.Count > 0) .OrderBy(f => f.ValueBinder.Items[0].Host is PFunction ? 1 : 0) .ToArray(); for (int i = 0; i < fields.Length; i++) { if (fields[i].ValueBinder.Items.Count == 0) { continue; } var fieldResult = buildImpl(trace, fields[i], attr.MappingCode); if (builder.Length > 0) { builder.Append(", "); } builder.Append(fieldResult.Source); } return(builder.ToString()); } return(""); } if (setter.Property.PropertyType != valueType || setter.Property.Name == "Source") { // on wpf if (setter.Property.Name == "Source") { return(this.MappingProvider.Casting(typeof(ImageSource), valueLine)); } // casting return(this.MappingProvider.Casting(setter.Property.PropertyType, valueLine)); } } } return(valueLine); }