using Simulator.Data; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Windows; using UVC.UI.Window.PropertyWindow; public class RobotArmProperty : MonoBehaviour { [SerializeField] private PropertyWindow propertyWindow; private void Awake() { propertyWindow.PropertyValueChanged += OnPropertyValueChanged; } public void SetProertyWindow(ComponentType type,ComponentDataBase data) { Debug.Log(data); InitRobotArmProperty(data as RobotArmDataClass); } void SaveChange(object source, object value, string name) { var path = PathIndexer.GetNodePath(source); Patch updateData = new Patch(); updateData.value = value; UpdateValueStack.AddPatch($"{path}.{name}", value); } public void InitRobotArmProperty(RobotArmDataClass robotArm) { List entries = new List { new StringProperty("name", "이름", robotArm.name) { IsReadOnly=true }, new StringProperty("label", "라벨", robotArm.label) { IsReadOnly=false }.Bind( setter: v => {robotArm.label = v;SaveChange(robotArm,v,"label"); } ), CreatePositionGroup(robotArm), new EnumProperty("display_mode_RobotArmSpeedPolicy", "로봇팔 속도 정책",robotArm.robot_arm_speed_policy.policy).Bind( setter: v=>{robotArm.robot_arm_speed_policy=PolicyFactory.Create(v.ToString());SaveChange(robotArm,v.ToString(),"robot_arm_speed_policy.type");} ), CreateRobotArmSpeedPolicy_Constant(robotArm), CreateRobotArmSpeedPolicy_Normal(robotArm), CreateRobotArmSpeedPolicy_Uniform(robotArm), CreateRobotArmSpeedPolicy_Exponential(robotArm), CreateRobotArmSpeedPolicy_Triangular(robotArm), new EnumProperty("display_mode_FailureRatePolicy", "고장률 정책",robotArm.failure_rate_policy.policy).Bind( setter: v=>{robotArm.failure_rate_policy=PolicyFactory.Create(v.ToString());SaveChange(robotArm,v.ToString(),"failure_rate_policy.type");} ), CreateFailureRatePolicy_Constant(robotArm), CreateFailureRatePolicy_Normal(robotArm), CreateFailureRatePolicy_Uniform(robotArm), CreateFailureRatePolicy_Exponential(robotArm), CreateFailureRatePolicy_Triangular(robotArm), new EnumProperty("display_mode_RepairTimePolicy", "수리 시간 정책",robotArm.repair_time_policy.policy).Bind( setter: v=>{robotArm.repair_time_policy=PolicyFactory.Create(v.ToString());SaveChange(robotArm,v.ToString(),"repair_time_policy.type");} ), CreateRepairTimePolicy_Constant(robotArm), CreateRepairTimePolicy_Normal(robotArm), CreateRepairTimePolicy_Uniform(robotArm), CreateRepairTimePolicy_Exponential(robotArm), CreateRepairTimePolicy_Triangular(robotArm), CreateInputsGroup(robotArm), CreateOutputsGroup(robotArm), CreateRequireResourceGroup(robotArm) }; propertyWindow.LoadMixedProperties(entries); HandleDisplayModeChanged_RobotArmSpeedPolicy(robotArm.robot_arm_speed_policy.policy.ToString()); HandleDisplayModeChanged_FailureRatePolicy(robotArm.failure_rate_policy.policy.ToString()); HandleDisplayModeChanged_RepairTimePolicy(robotArm.repair_time_policy.policy.ToString()); CreateCostGroup(robotArm); } private void OnPropertyValueChanged(object sender, PropertyValueChangedEventArgs e) { Debug.Log($"[PropertyChanged] Id:{e.PropertyId}, Type:{e.PropertyType}, Value:{e.NewValue}"); // 동적 그룹 표시/비표시 테스트 if (e.PropertyId == "display_mode_RobotArmSpeedPolicy") { string selectedMode = e.NewValue.ToString(); HandleDisplayModeChanged_RobotArmSpeedPolicy(selectedMode); } if (e.PropertyId == "display_mode_FailureRatePolicy") { string selectedMode = e.NewValue.ToString(); HandleDisplayModeChanged_FailureRatePolicy(selectedMode); } if (e.PropertyId == "display_mode_RepairTimePolicy") { string selectedMode = e.NewValue.ToString(); HandleDisplayModeChanged_RepairTimePolicy(selectedMode); } } private PropertyGroup CreatePositionGroup(RobotArmDataClass robotArm) { var group = new PropertyGroup("robotArm_position", "위치 및 회전", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("x_position", "X 좌표(m)", robotArm.physical.position.x) { }.Bind( setter: v => {robotArm.physical.position.x = v;SaveChange(robotArm,v,"physical.position.x"); } ), new FloatProperty("y_position", "y 좌표(m)", robotArm.physical.position.y) { }.Bind( setter: v => {robotArm.physical.position.y = v;SaveChange(robotArm,v,"physical.position.y"); } ), new FloatProperty("orientation", "회전(°)", robotArm.physical.orientation) { }.Bind( setter: v => {robotArm.physical.orientation = v;SaveChange(robotArm,v,"physical.orientation");propertyWindow.ApplyExternalValue("orientation",RotationSnap.snaporientaion(v),false); } ), }); return group; } #region 로봇팔 속도 정책 private PropertyGroup CreateRobotArmSpeedPolicy_Constant(RobotArmDataClass robotArm) { var group = new PropertyGroup("RobotArmSpeedPolicy_Constant", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RobotArmSpeedPolicy_Constant_Value", "상수 값", (robotArm.robot_arm_speed_policy as Policy_Constant) ?.value ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Constant).value = v;SaveChange(robotArm,v,"robot_arm_speed_policy.value"); } ), }); return group; } private PropertyGroup CreateRobotArmSpeedPolicy_Normal(RobotArmDataClass robotArm) { var group = new PropertyGroup("RobotArmSpeedPolicy_Normal", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RobotArmSpeedPolicy_Normal_Mean", "정규 분포 표준치", (robotArm.robot_arm_speed_policy as Policy_Normal) ?.mean ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Normal).mean = v;SaveChange(robotArm,v,"robot_arm_speed_policy.mean"); } ), new FloatProperty("RobotArmSpeedPolicy_Normal_Gap", "정규 분포 표준 편차", (robotArm.robot_arm_speed_policy as Policy_Normal) ?.stddev ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Normal).stddev = v;SaveChange(robotArm,v,"robot_arm_speed_policy.stddev"); } ), }); return group; } private PropertyGroup CreateRobotArmSpeedPolicy_Uniform(RobotArmDataClass robotArm) { var group = new PropertyGroup("RobotArmSpeedPolicy_Uniform", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RobotArmSpeedPolicy_Uniform_Min", "균등 분포 최소값", (robotArm.robot_arm_speed_policy as Policy_Uniform) ?.min_val ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Uniform).min_val = v;SaveChange(robotArm,v,"robot_arm_speed_policy.min_val"); } ), new FloatProperty("RobotArmSpeedPolicy_Uniform_Max", "균등 분포 최대값", (robotArm.robot_arm_speed_policy as Policy_Uniform) ?.max_val ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Uniform).max_val = v;SaveChange(robotArm,v,"robot_arm_speed_policy.max_val"); } ), }); return group; } private PropertyGroup CreateRobotArmSpeedPolicy_Exponential(RobotArmDataClass robotArm) { var group = new PropertyGroup("RobotArmSpeedPolicy_Exponential", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RobotArmSpeedPolicy_Exponential_Mean", "지수 분포 평균치", (robotArm.robot_arm_speed_policy as Policy_Exponential) ?.mean ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Exponential).mean = v;SaveChange(robotArm,v,"robot_arm_speed_policy.mean"); } ), }); return group; } private PropertyGroup CreateRobotArmSpeedPolicy_Triangular(RobotArmDataClass robotArm) { var group = new PropertyGroup("RobotArmSpeedPolicy_Triangular", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RobotArmSpeedPolicy_Triangular_Min", "지수 분포 최소값", (robotArm.robot_arm_speed_policy as Policy_Triangular) ?.min_val ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Triangular).min_val = v;SaveChange(robotArm,v,"robot_arm_speed_policy.min_val"); } ), new FloatProperty("RobotArmSpeedPolicy_Triangular_Mean", "지수 분포 최빈값", (robotArm.robot_arm_speed_policy as Policy_Triangular) ?.mode ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Triangular).mode = v;SaveChange(robotArm,v,"robot_arm_speed_policy.mode"); } ), new FloatProperty("RobotArmSpeedPolicy_Triangular_Max", "지수 분포 최대값", (robotArm.robot_arm_speed_policy as Policy_Triangular) ?.max_val ?? 0f) { }.Bind( setter: v => {(robotArm.robot_arm_speed_policy as Policy_Triangular).max_val = v;SaveChange(robotArm,v,"robot_arm_speed_policy.max_val"); } ), }); return group; } private void HandleDisplayModeChanged_RobotArmSpeedPolicy(string mode) { // 모든 조건부 그룹 숨김 propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Constant", false); propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Normal", false); propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Uniform", false); propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Exponential", false); propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Triangular", false); // 선택된 모드에 따라 해당 그룹만 표시 switch (mode) { case "Constant": propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Constant", true); break; case "Normal": propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Normal", true); break; case "Uniform": propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Uniform", true); break; case "Exponential": propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Exponential", true); break; case "Triangular": propertyWindow.SetGroupVisibility("RobotArmSpeedPolicy_Triangular", true); break; } } #endregion #region 고장률 정책 private PropertyGroup CreateFailureRatePolicy_Constant(RobotArmDataClass robotArm) { var group = new PropertyGroup("FailureRatePolicy_Constant", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("FailureRatePolicy_Constant_Value", "상수 값", (robotArm.failure_rate_policy as Policy_Constant) ?.value ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Constant).value = v;SaveChange(robotArm,v,"failure_rate_policy.value"); } ), }); return group; } private PropertyGroup CreateFailureRatePolicy_Normal(RobotArmDataClass robotArm) { var group = new PropertyGroup("FailureRatePolicy_Normal", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("FailureRatePolicy_Normal_Mean", "정규 분포 표준치", (robotArm.failure_rate_policy as Policy_Normal) ?.mean ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Normal).mean = v;SaveChange(robotArm,v,"failure_rate_policy.mean"); } ), new FloatProperty("FailureRatePolicy_Normal_Gap", "정규 분포 표준 편차", (robotArm.failure_rate_policy as Policy_Normal) ?.stddev ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Normal).stddev = v;SaveChange(robotArm,v,"failure_rate_policy.stddev"); } ), }); return group; } private PropertyGroup CreateFailureRatePolicy_Uniform(RobotArmDataClass robotArm) { var group = new PropertyGroup("FailureRatePolicy_Uniform", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("FailureRatePolicy_Uniform_Min", "균등 분포 최소값", (robotArm.failure_rate_policy as Policy_Uniform) ?.min_val ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Uniform).min_val = v;SaveChange(robotArm,v,"failure_rate_policy.min_val"); } ), new FloatProperty("FailureRatePolicy_Uniform_Max", "균등 분포 최대값", (robotArm.failure_rate_policy as Policy_Uniform) ?.max_val ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Uniform).max_val = v;SaveChange(robotArm,v,"failure_rate_policy.max_val"); } ), }); return group; } private PropertyGroup CreateFailureRatePolicy_Exponential(RobotArmDataClass robotArm) { var group = new PropertyGroup("FailureRatePolicy_Exponential", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("FailureRatePolicy_Exponential_Mean", "지수 분포 평균치", (robotArm.failure_rate_policy as Policy_Exponential) ?.mean ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Exponential).mean = v;SaveChange(robotArm,v,"failure_rate_policy.mean"); } ), }); return group; } private PropertyGroup CreateFailureRatePolicy_Triangular(RobotArmDataClass robotArm) { var group = new PropertyGroup("FailureRatePolicy_Triangular", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("FailureRatePolicy_Triangular_Min", "지수 분포 최소값", (robotArm.failure_rate_policy as Policy_Triangular) ?.min_val ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Triangular).min_val = v;SaveChange(robotArm,v,"failure_rate_policy.min_val"); } ), new FloatProperty("FailureRatePolicy_Triangular_Mean", "지수 분포 최빈값", (robotArm.failure_rate_policy as Policy_Triangular) ?.mode ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Triangular).mode = v;SaveChange(robotArm,v,"failure_rate_policy.mode"); } ), new FloatProperty("FailureRatePolicy_Triangular_Max", "지수 분포 최대값", (robotArm.failure_rate_policy as Policy_Triangular) ?.max_val ?? 0f) { }.Bind( setter: v => {(robotArm.failure_rate_policy as Policy_Triangular).max_val = v;SaveChange(robotArm,v,"failure_rate_policy.max_val"); } ), }); return group; } private void HandleDisplayModeChanged_FailureRatePolicy(string mode) { // 모든 조건부 그룹 숨김 propertyWindow.SetGroupVisibility("FailureRatePolicy_Constant", false); propertyWindow.SetGroupVisibility("FailureRatePolicy_Normal", false); propertyWindow.SetGroupVisibility("FailureRatePolicy_Uniform", false); propertyWindow.SetGroupVisibility("FailureRatePolicy_Exponential", false); propertyWindow.SetGroupVisibility("FailureRatePolicy_Triangular", false); // 선택된 모드에 따라 해당 그룹만 표시 switch (mode) { case "Constant": propertyWindow.SetGroupVisibility("FailureRatePolicy_Constant", true); break; case "Normal": propertyWindow.SetGroupVisibility("FailureRatePolicy_Normal", true); break; case "Uniform": propertyWindow.SetGroupVisibility("FailureRatePolicy_Uniform", true); break; case "Exponential": propertyWindow.SetGroupVisibility("FailureRatePolicy_Exponential", true); break; case "Triangular": propertyWindow.SetGroupVisibility("FailureRatePolicy_Triangular", true); break; } } #endregion #region 수리 시간 정책 private PropertyGroup CreateRepairTimePolicy_Constant(RobotArmDataClass robotArm) { var group = new PropertyGroup("RepairTimePolicy_Constant", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RepairTimePolicy_Constant_Value", "상수 값", (robotArm.repair_time_policy as Policy_Constant) ?.value ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Constant).value = v;SaveChange(robotArm,v,"repair_time_policy.value"); } ), }); return group; } private PropertyGroup CreateRepairTimePolicy_Normal(RobotArmDataClass robotArm) { var group = new PropertyGroup("RepairTimePolicy_Normal", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RepairTimePolicy_Normal_Mean", "정규 분포 표준치", (robotArm.repair_time_policy as Policy_Normal) ?.mean ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Normal).mean = v;SaveChange(robotArm,v,"repair_time_policy.mean"); } ), new FloatProperty("RepairTimePolicy_Normal_Gap", "정규 분포 표준 편차", (robotArm.repair_time_policy as Policy_Normal) ?.stddev ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Normal).stddev = v;SaveChange(robotArm,v,"repair_time_policy.stddev"); } ), }); return group; } private PropertyGroup CreateRepairTimePolicy_Uniform(RobotArmDataClass robotArm) { var group = new PropertyGroup("RepairTimePolicy_Uniform", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RepairTimePolicy_Uniform_Min", "균등 분포 최소값", (robotArm.repair_time_policy as Policy_Uniform) ?.min_val ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Uniform).min_val = v;SaveChange(robotArm,v,"repair_time_policy.min_val"); } ), new FloatProperty("RepairTimePolicy_Uniform_Max", "균등 분포 최대값", (robotArm.repair_time_policy as Policy_Uniform) ?.max_val ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Uniform).max_val = v;SaveChange(robotArm,v,"repair_time_policy.max_val"); } ), }); return group; } private PropertyGroup CreateRepairTimePolicy_Exponential(RobotArmDataClass robotArm) { var group = new PropertyGroup("RepairTimePolicy_Exponential", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RepairTimePolicy_Exponential_Mean", "지수 분포 평균치", (robotArm.repair_time_policy as Policy_Exponential) ?.mean ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Exponential).mean = v;SaveChange(robotArm,v,"repair_time_policy.mean"); } ), }); return group; } private PropertyGroup CreateRepairTimePolicy_Triangular(RobotArmDataClass robotArm) { var group = new PropertyGroup("RepairTimePolicy_Triangular", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("RepairTimePolicy_Triangular_Min", "지수 분포 최소값", (robotArm.repair_time_policy as Policy_Triangular) ?.min_val ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Triangular).min_val = v;SaveChange(robotArm,v,"repair_time_policy.min_val"); } ), new FloatProperty("RepairTimePolicy_Triangular_Mean", "지수 분포 최빈값", (robotArm.repair_time_policy as Policy_Triangular) ?.mode ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Triangular).mode = v;SaveChange(robotArm,v,"repair_time_policy.mode"); } ), new FloatProperty("RepairTimePolicy_Triangular_Max", "지수 분포 최대값", (robotArm.repair_time_policy as Policy_Triangular) ?.max_val ?? 0f) { }.Bind( setter: v => {(robotArm.repair_time_policy as Policy_Triangular).max_val = v;SaveChange(robotArm,v,"repair_time_policy.max_val"); } ), }); return group; } private void HandleDisplayModeChanged_RepairTimePolicy(string mode) { // 모든 조건부 그룹 숨김 propertyWindow.SetGroupVisibility("RepairTimePolicy_Constant", false); propertyWindow.SetGroupVisibility("RepairTimePolicy_Normal", false); propertyWindow.SetGroupVisibility("RepairTimePolicy_Uniform", false); propertyWindow.SetGroupVisibility("RepairTimePolicy_Exponential", false); propertyWindow.SetGroupVisibility("RepairTimePolicy_Triangular", false); // 선택된 모드에 따라 해당 그룹만 표시 switch (mode) { case "Constant": propertyWindow.SetGroupVisibility("RepairTimePolicy_Constant", true); break; case "Normal": propertyWindow.SetGroupVisibility("RepairTimePolicy_Normal", true); break; case "Uniform": propertyWindow.SetGroupVisibility("RepairTimePolicy_Uniform", true); break; case "Exponential": propertyWindow.SetGroupVisibility("RepairTimePolicy_Exponential", true); break; case "Triangular": propertyWindow.SetGroupVisibility("RepairTimePolicy_Triangular", true); break; } } #endregion PropertyGroup CreateInputsGroup(RobotArmDataClass robotArm) { var group = new PropertyGroup("InputConnect", "입력 연결", isExpanded: true); foreach(var input in robotArm.inputs) { var property = new IntProperty($"{input.target}prefab", input.target, input.required_items).Bind ( setter: v => { input.required_items = v; SaveChange(input, v, "required_items"); } ); group.AddItem(property); } return group; } PropertyGroup CreateOutputsGroup(RobotArmDataClass robotArm) { var group = new PropertyGroup("OutputConnect", "출력 연결", isExpanded: true); foreach (var output in robotArm.outputs) { var property = new IntProperty($"{output.target}prefab", output.target, output.required_items).Bind ( setter: v => { output.required_items = v; SaveChange(output, v, "required_items"); } ); group.AddItem(property); } return group; } private PropertyGroup CreateRequireResourceGroup(RobotArmDataClass robotArm) { var group = new PropertyGroup("RequireResource", "자원 할당", isExpanded: true); // 1) required_resources 인덱스화 var requiredIndex = BuildRequiredIndex(robotArm); int count = 0; foreach (var resource in ComponentsManager.logicDetailData.infrastructure.resources) { if (!string.Equals(resource.type, "worker")) continue; // 2) 매칭 키 결정: 여기서는 resource.name을 키로 쓴다고 가정 var key = resource.name; // ★ label 말고 name/id 권장 bool isRequired = key != null && requiredIndex.ContainsKey(key); // 3) 초기값을 isRequired로 var property = new BoolProperty($"required_resource[{count++}]", resource.label, isRequired); // 4) (선택) 변경 시 processor.required_resources 업데이트 + Patch 저장까지 Bind로 연결 property.Bind(setter: v => { SetRequiredResource(robotArm, key, v); // SaveChange(processor or sourceRoot, processorRequiredPath...) 형태로 패치 기록 }); group.AddItem(property); } return group; } private void SetRequiredResource(RobotArmDataClass robotArm, string resourceName, bool required) { if (string.IsNullOrEmpty(resourceName)) return; robotArm.required_resources ??= new List(); int idx = robotArm.required_resources.FindIndex(x => x != null && x.name == resourceName); if (required) { if (idx < 0) { robotArm.required_resources.Add(new Required_Resources { name = resourceName, count = 1, selection_policy = "random" // 기본값 정책은 규칙에 맞춰 결정 }); } else { // 이미 있으면 유지 (필요 시 count/policy 기본 보정) } } else { if (idx >= 0) robotArm.required_resources.RemoveAt(idx); } } private Dictionary BuildRequiredIndex(RobotArmDataClass robotArm) { var dict = new Dictionary(StringComparer.Ordinal); if (robotArm.required_resources == null) return dict; foreach (var rr in robotArm.required_resources) { if (rr?.name == null) continue; dict[rr.name] = rr; } return dict; } PropertyGroup CreateCostGroup(RobotArmDataClass robotArm) { var group = new PropertyGroup("CostSetting", "비용 설정", isExpanded: true); group.AddItems(new IPropertyItem[] { new IntProperty("Operating_Cost_Per_Hour", "시간당 가동 비용", robotArm.operating_cost_per_hour) { }.Bind( setter: v => {robotArm.operating_cost_per_hour = v;SaveChange(robotArm,v,"operating_cost_per_hour"); } ), new IntProperty("Idle_Cost_Per_Hour", "시간당 대기 비용", robotArm.idle_cost_per_hour) { }.Bind( setter: v => {robotArm.idle_cost_per_hour = v;SaveChange(robotArm,v,"idle_cost_per_hour"); } ), new IntProperty("Failure_Cost", "고장 1회 손실 비용", robotArm.failure_cost) { }.Bind( setter: v => {robotArm.failure_cost = v;SaveChange(robotArm,v,"failure_cost"); } ), new IntProperty("repair_cost_per_hour", "시간당 수리 비용", robotArm.repair_cost_per_hour) { }.Bind( setter: v => {robotArm.repair_cost_per_hour = v;SaveChange(robotArm,v,"repair_cost_per_hour"); } ), }); return group; } }