From b69cca21ac9f26b6473d8f3eac000ebcd466b495 Mon Sep 17 00:00:00 2001 From: sladro Date: Wed, 31 Dec 2025 09:58:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8C=B9=E9=85=8D=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CadParamPluging.csproj | 1 + Common/DropdownOptions.cs | 1 + UI/ParamDrawingPanel.cs | 290 +++++++++++++++--------------------- UI/SettingsForm.cs | 155 +++++++++++++------ UI/TemplateSelectionItem.cs | 30 ++++ 5 files changed, 263 insertions(+), 214 deletions(-) create mode 100644 UI/TemplateSelectionItem.cs diff --git a/CadParamPluging.csproj b/CadParamPluging.csproj index 496bd60..778600f 100644 --- a/CadParamPluging.csproj +++ b/CadParamPluging.csproj @@ -118,6 +118,7 @@ Form + diff --git a/Common/DropdownOptions.cs b/Common/DropdownOptions.cs index ce19aa9..f38200e 100644 --- a/Common/DropdownOptions.cs +++ b/Common/DropdownOptions.cs @@ -9,6 +9,7 @@ namespace CadParamPluging.Common public List ProcessMethods { get; set; } public List StructuralFeatures { get; set; } public List SpecialConditions { get; set; } + public string DefaultTemplatePath { get; set; } public DropdownOptions() { diff --git a/UI/ParamDrawingPanel.cs b/UI/ParamDrawingPanel.cs index 4b6290f..484be1c 100644 --- a/UI/ParamDrawingPanel.cs +++ b/UI/ParamDrawingPanel.cs @@ -21,7 +21,9 @@ namespace CadParamPluging.UI private readonly ComboBox _cbDrawingType; private readonly ComboBox _cbSheetSize; private readonly ComboBox _cbScale; - private Label _lblTemplateInfo; + private ComboBox _cbTemplateList; + private Button _btnRefreshTemplates; + private TextBox _txtLog; private TextBox _txtTemplatePath; @@ -53,6 +55,18 @@ namespace CadParamPluging.UI _cbSheetSize = CreateComboBox(dropdownOptions.StructuralFeatures); _cbScale = CreateComboBox(dropdownOptions.SpecialConditions); + // Initialize template controls here in constructor to follow readonly/non-readonly best practices, + // though they are no longer readonly. + _btnRefreshTemplates = new Button { Text = "刷新列表", AutoSize = true }; + _btnRefreshTemplates.Click += (_, __) => RefreshTemplateList(); + + _cbTemplateList = new ComboBox + { + DropDownStyle = ComboBoxStyle.DropDownList, + Dock = DockStyle.Fill + }; + _cbTemplateList.SelectedIndexChanged += OnTemplateSelectionChanged; + var templateGroup = BuildTemplateGroup(); var drawingGroup = BuildDrawingGroup(); var actionPanel = BuildActionPanel(); @@ -62,8 +76,26 @@ namespace CadParamPluging.UI layout.Controls.Add(drawingGroup, 0, 1); layout.Controls.Add(actionPanel, 0, 2); layout.Controls.Add(logGroup, 0, 3); - + Controls.Add(layout); + + if (!string.IsNullOrWhiteSpace(dropdownOptions.DefaultTemplatePath) + && Directory.Exists(dropdownOptions.DefaultTemplatePath)) + { + _selectedFolderPath = dropdownOptions.DefaultTemplatePath; + _txtTemplatePath.Text = dropdownOptions.DefaultTemplatePath; + _cadFilePaths = LoadCadFilesFromFolder(_selectedFolderPath); + + // Use BeginInvoke to ensure UI is ready + var timer = new Timer { Interval = 100 }; + timer.Tick += (s, e) => + { + timer.Stop(); + timer.Dispose(); + RefreshTemplateList(); + }; + timer.Start(); + } } private GroupBox BuildTemplateGroup() @@ -104,19 +136,8 @@ namespace CadParamPluging.UI grid.Controls.Add(btnSelect, 0, 4); grid.Controls.Add(_txtTemplatePath, 1, 4); - var btnMatch = new Button { Text = "匹配模板", AutoSize = true }; - btnMatch.Click += (_, __) => OnMatchTemplate(); - - _lblTemplateInfo = new Label - { - Text = "未匹配模板", - AutoSize = true, - ForeColor = Color.DarkBlue, - TextAlign = ContentAlignment.MiddleLeft - }; - - grid.Controls.Add(btnMatch, 0, 5); - grid.Controls.Add(_lblTemplateInfo, 1, 5); + grid.Controls.Add(_btnRefreshTemplates, 0, 5); + grid.Controls.Add(_cbTemplateList, 1, 5); group.Controls.Add(grid); return group; @@ -190,162 +211,105 @@ namespace CadParamPluging.UI return group; } - private void OnMatchTemplate() + private void RefreshTemplateList() { try { - if (_cadFilePaths == null || _cadFilePaths.Length == 0) - { - AppendLog("请先选择路径。"); - return; - } - - AppendLog("开始匹配模板..."); - - var tplParams = CollectTemplateParams(); - - foreach (var cadPath in _cadFilePaths) - { - if (string.IsNullOrWhiteSpace(cadPath) || !File.Exists(cadPath)) - { - continue; - } - - // 1) 优先按 Layout(PaperSpace) 匹配 - var layoutCandidates = TemplateLayoutAnnotationExtractor.ExtractPerLayout(cadPath); - var layoutMatch = layoutCandidates.FirstOrDefault(c => LayoutMatches(c, tplParams)); - if (layoutMatch != null) - { - _selectedTemplate = new TemplateInfo - { - Name = Path.GetFileName(cadPath), - FilePath = cadPath - }; - - _selectedTemplate.LayoutName = layoutMatch.LayoutName; - _selectedModelWindow = null; - _selectedSheetName = layoutMatch.LayoutName; - - _lblTemplateInfo.Text = $"{cadPath} | {layoutMatch.LayoutName}"; - AppendLog($"匹配成功: {Path.GetFileName(cadPath)} | Layout: {layoutMatch.LayoutName}"); - return; - } - - // 2) Layout 未命中时,尝试按 ModelSpace 窗口候选匹配 - var modelCandidates = TemplateModelSheetExtractor.ExtractCandidates(cadPath); - var modelMatch = modelCandidates.FirstOrDefault(c => ModelMatches(c, tplParams)); - if (modelMatch != null) - { - _selectedTemplate = new TemplateInfo - { - Name = Path.GetFileName(cadPath), - FilePath = cadPath - }; - - _selectedTemplate.LayoutName = null; - _selectedModelWindow = modelMatch.Window; - _selectedSheetName = modelMatch.Name; - - _lblTemplateInfo.Text = $"{cadPath} | {modelMatch.Name}"; - AppendLog($"匹配成功: {Path.GetFileName(cadPath)} | Model: {modelMatch.Name}"); - return; - } - } - + _cbTemplateList.Items.Clear(); _selectedTemplate = null; _selectedModelWindow = null; _selectedSheetName = null; - _lblTemplateInfo.Text = "未匹配模板"; - AppendLog("未找到匹配模板。"); - } - catch (BusinessException bex) - { - if (_selectedTemplate != null) + + if (_cadFilePaths == null || _cadFilePaths.Length == 0) { - _selectedTemplate.LayoutName = null; + AppendLog("未加载CAD文件,请先选择路径。"); + return; + } + + AppendLog("开始扫描模板..."); + var items = new System.Collections.Generic.List(); + + foreach (var cadPath in _cadFilePaths) + { + if (string.IsNullOrWhiteSpace(cadPath) || !File.Exists(cadPath)) continue; + + try + { + // 1) Layouts + var layouts = TemplateLayoutAnnotationExtractor.ExtractPerLayout(cadPath); + foreach (var l in layouts) + { + items.Add(new TemplateSelectionItem(new TemplateInfo + { + Name = Path.GetFileName(cadPath), + FilePath = cadPath, + LayoutName = l.LayoutName + })); + } + + // 2) Model Space Windows + var models = TemplateModelSheetExtractor.ExtractCandidates(cadPath); + foreach (var m in models) + { + var item = new TemplateSelectionItem(new TemplateInfo + { + Name = Path.GetFileName(cadPath), + FilePath = cadPath, + LayoutName = null // Model space + }); + item.ModelWindow = m.Window; + // Hint: TemplateInfo doesn't hold the 'Name' of the sheet if it's ModelSpace named candidate + // But usually DisplayName handles it. We can store the sheet name in Info.LayoutName or just use ToString override + // Actually TemplateInfo.LayoutName is used for opening. + // For model space candidates, we usually matched them by 'Name' in auto-match. + // Here we just list them. + items.Add(item); + } + } + catch (Exception ex) + { + Console.WriteLine(ex); // silent fail for single file + } + } + + if (items.Count == 0) + { + AppendLog("未在路径下找到有效的模板/布局。"); + return; + } + + _cbTemplateList.Items.AddRange(items.Cast().ToArray()); + AppendLog($"已加载 {items.Count} 个模板选项。"); + + if (_cbTemplateList.Items.Count > 0) + { + _cbTemplateList.SelectedIndex = 0; } - _selectedModelWindow = null; - _selectedSheetName = null; - _lblTemplateInfo.Text = _selectedTemplate?.FilePath ?? "未匹配图纸"; - AppendLog($"图纸匹配错误: {bex.Message}"); } catch (Exception ex) { - if (_selectedTemplate != null) - { - _selectedTemplate.LayoutName = null; - } + AppendLog($"刷新模板列表失败: {ex.Message}"); + Logger.Error("RefreshTemplateList", ex); + } + } + + private void OnTemplateSelectionChanged(object sender, EventArgs e) + { + var item = _cbTemplateList.SelectedItem as TemplateSelectionItem; + if (item == null) + { + _selectedTemplate = null; _selectedModelWindow = null; _selectedSheetName = null; - _lblTemplateInfo.Text = _selectedTemplate?.FilePath ?? "未匹配图纸"; - AppendLog($"匹配失败: {ex.Message}"); - Logger.Error("MatchLayout", ex); - } - } - - private static bool LayoutMatches(LayoutAnnotation ann, TemplateParams tplParams) - { - if (ann == null || tplParams == null) - { - return false; + return; } - return ContainsIgnoreCase(ann.DeliveryStatuses, tplParams.ProjectType) - && ContainsIgnoreCase(ann.ProcessMethods, tplParams.DrawingType) - && ContainsIgnoreCase(ann.StructuralFeatures, tplParams.SheetSize) - && ContainsIgnoreCase(ann.SpecialConditions, tplParams.Scale); - } - - private static bool ContainsIgnoreCase(System.Collections.Generic.IEnumerable values, string expected) - { - if (string.IsNullOrWhiteSpace(expected)) - { - return true; - } - - if (values == null) - { - return false; - } - - var exp = NormalizeValue(expected); - return values.Any(v => string.Equals(NormalizeValue(v), exp, StringComparison.OrdinalIgnoreCase)); - } - - private static string NormalizeValue(string s) - { - if (string.IsNullOrWhiteSpace(s)) - { - return string.Empty; - } - - var trimmed = s.Trim(); - var chars = trimmed.Where(c => !char.IsWhiteSpace(c)).ToArray(); - return new string(chars); - } - - private static string Preview(System.Collections.Generic.IEnumerable values) - { - if (values == null) - { - return "(无)"; - } - - var arr = values.Where(v => !string.IsNullOrWhiteSpace(v)).Select(v => v.Trim()).ToArray(); - return arr.Length == 0 ? "(无)" : string.Join("/", arr); - } - - private static bool ModelMatches(ModelSheetCandidate ann, TemplateParams tplParams) - { - if (ann == null || tplParams == null) - { - return false; - } - - return ContainsIgnoreCase(ann.DeliveryStatuses, tplParams.ProjectType) - && ContainsIgnoreCase(ann.ProcessMethods, tplParams.DrawingType) - && ContainsIgnoreCase(ann.StructuralFeatures, tplParams.SheetSize) - && ContainsIgnoreCase(ann.SpecialConditions, tplParams.Scale); + _selectedTemplate = item.Info; + _selectedModelWindow = item.ModelWindow; + _selectedSheetName = item.ToString(); // Use the display string as sheet name reference + + // Log if needed + // AppendLog($"已选择: {_selectedSheetName}"); } private void OnSelectTemplate() @@ -387,6 +351,8 @@ namespace CadParamPluging.UI { AppendLog($"... 还有 {_cadFilePaths.Length - 10} 个文件"); } + + RefreshTemplateList(); } } } @@ -562,20 +528,10 @@ namespace CadParamPluging.UI if (_selectedTemplate == null || string.IsNullOrWhiteSpace(_selectedTemplate.FilePath)) { - AppendLog("请先选择路径并匹配模板。"); + AppendLog("请先选择并确认模板(下拉框)。"); return; } - if (string.IsNullOrWhiteSpace(_selectedTemplate.LayoutName) && !_selectedModelWindow.HasValue) - { - AppendLog("未匹配图纸,尝试自动匹配..."); - OnMatchTemplate(); - if (_selectedTemplate == null || (string.IsNullOrWhiteSpace(_selectedTemplate.LayoutName) && !_selectedModelWindow.HasValue)) - { - return; - } - } - var templateKey = TemplateKeyBuilder.Build(tplParams); if (string.IsNullOrWhiteSpace(templateKey)) { diff --git a/UI/SettingsForm.cs b/UI/SettingsForm.cs index 5d2de89..3a5bb14 100644 --- a/UI/SettingsForm.cs +++ b/UI/SettingsForm.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using System.IO; using System.Linq; using System.Windows.Forms; using CadParamPluging.Common; @@ -12,102 +13,159 @@ namespace CadParamPluging.UI private readonly ListBox _lbProcessMethods; private readonly ListBox _lbStructuralFeatures; private readonly ListBox _lbSpecialConditions; + private readonly TextBox _txtDefaultTemplatePath; public DropdownOptions Result { get; private set; } public SettingsForm(DropdownOptions current) { Text = "设置"; - Size = new Size(560, 420); + Size = new Size(600, 500); StartPosition = FormStartPosition.CenterScreen; FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; MinimizeBox = false; ShowInTaskbar = false; + Font = SystemFonts.MessageBoxFont; // Use system font for consistent look - var layout = new TableLayoutPanel + var mainLayout = new TableLayoutPanel { Dock = DockStyle.Fill, - Padding = new Padding(10), - RowCount = 2, + Padding = new Padding(12), + RowCount = 3, ColumnCount = 1 }; - layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100f)); // Content area - layout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Buttons area + mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Default Path + mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 100f)); // Tabs + mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // Buttons _lbDeliveryStatuses = new ListBox(); _lbProcessMethods = new ListBox(); _lbStructuralFeatures = new ListBox(); _lbSpecialConditions = new ListBox(); + _txtDefaultTemplatePath = new TextBox { Dock = DockStyle.Fill, ReadOnly = true }; var options = (current ?? DropdownOptions.CreateDefault()).Clone(); options.Normalize(); + _txtDefaultTemplatePath.Text = options.DefaultTemplatePath ?? string.Empty; FillList(_lbDeliveryStatuses, options.DeliveryStatuses); FillList(_lbProcessMethods, options.ProcessMethods); FillList(_lbStructuralFeatures, options.StructuralFeatures); FillList(_lbSpecialConditions, options.SpecialConditions); - var tabs = new TabControl + // 1. Default Path Section + var pathGroup = new GroupBox { - Dock = DockStyle.Fill + Text = "默认模板路径", + Dock = DockStyle.Fill, + AutoSize = true, + Padding = new Padding(6) }; + var pathGrid = new TableLayoutPanel + { + Dock = DockStyle.Top, + AutoSize = true, + ColumnCount = 2, + RowCount = 1, + Padding = new Padding(4) + }; + pathGrid.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f)); + pathGrid.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + + var btnBrowsePath = new Button + { + Text = "浏览...", + AutoSize = true, + Height = _txtDefaultTemplatePath.Height, // visually match + Anchor = AnchorStyles.Left | AnchorStyles.Right + }; + btnBrowsePath.Click += (_, __) => OnBrowseDefaultPath(); + + pathGrid.Controls.Add(_txtDefaultTemplatePath, 0, 0); + pathGrid.Controls.Add(btnBrowsePath, 1, 0); + pathGroup.Controls.Add(pathGrid); + + // 2. Tabs Section + var tabs = new TabControl { Dock = DockStyle.Fill }; tabs.TabPages.Add(BuildEditableTab("交付状态", _lbDeliveryStatuses)); tabs.TabPages.Add(BuildEditableTab("工艺方法", _lbProcessMethods)); tabs.TabPages.Add(BuildEditableTab("结构特征", _lbStructuralFeatures)); tabs.TabPages.Add(BuildEditableTab("特殊条件", _lbSpecialConditions)); - // Bottom area - var bottom = new TableLayoutPanel - { - Dock = DockStyle.Fill, - ColumnCount = 2, - RowCount = 1 + // 3. Bottom Section (Separated into Left (Tools) and Right (Dialog)) + var bottomGrid = new TableLayoutPanel + { + Dock = DockStyle.Fill, + RowCount = 1, + ColumnCount = 2, + AutoSize = true, + Margin = new Padding(0, 8, 0, 0) // Top margin for spacing }; - bottom.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f)); - bottom.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + bottomGrid.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f)); + bottomGrid.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - var flowLeft = new FlowLayoutPanel - { - Dock = DockStyle.Fill, - FlowDirection = FlowDirection.LeftToRight, - AutoSize = true + // Left tools + var leftTools = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + AutoSize = true, + FlowDirection = FlowDirection.LeftToRight }; - var btnParamCatalog = new Button { Text = "参数总表...", AutoSize = true }; + var btnParamCatalog = new Button { Text = "参数总表", AutoSize = true }; btnParamCatalog.Click += (_, __) => OnOpenParamCatalog(); - - var btnTemplateBinding = new Button { Text = "模板参数绑定...", AutoSize = true }; + + var btnTemplateBinding = new Button { Text = "模板绑定", AutoSize = true }; btnTemplateBinding.Click += (_, __) => OnOpenTemplateBinding(); - flowLeft.Controls.Add(btnParamCatalog); - flowLeft.Controls.Add(btnTemplateBinding); + leftTools.Controls.Add(btnParamCatalog); + leftTools.Controls.Add(btnTemplateBinding); - var flowRight = new FlowLayoutPanel + // Right actions + var rightActions = new FlowLayoutPanel { Dock = DockStyle.Fill, - FlowDirection = FlowDirection.RightToLeft, - AutoSize = true + AutoSize = true, + FlowDirection = FlowDirection.RightToLeft }; - - var btnCancel = new Button { Text = "取消", DialogResult = DialogResult.Cancel }; - var btnOk = new Button { Text = "确定" }; + var btnCancel = new Button { Text = "取消", DialogResult = DialogResult.Cancel, Width = 80 }; + var btnOk = new Button { Text = "确定", Width = 80 }; btnOk.Click += (_, __) => OnOk(); - flowRight.Controls.Add(btnCancel); - flowRight.Controls.Add(btnOk); + rightActions.Controls.Add(btnCancel); // Add in reverse order due to RightToLeft flow + rightActions.Controls.Add(btnOk); - bottom.Controls.Add(flowLeft, 0, 0); - bottom.Controls.Add(flowRight, 1, 0); + bottomGrid.Controls.Add(leftTools, 0, 0); + bottomGrid.Controls.Add(rightActions, 1, 0); - layout.Controls.Add(tabs, 0, 0); - layout.Controls.Add(bottom, 0, 1); + // Assemble Main + mainLayout.Controls.Add(pathGroup, 0, 0); + mainLayout.Controls.Add(tabs, 0, 1); + mainLayout.Controls.Add(bottomGrid, 0, 2); + + Controls.Add(mainLayout); - Controls.Add(layout); - AcceptButton = btnOk; CancelButton = btnCancel; } + private void OnBrowseDefaultPath() + { + using (var dialog = new FolderBrowserDialog()) + { + dialog.Description = "选择默认模板路径"; + if (System.IO.Directory.Exists(_txtDefaultTemplatePath.Text)) + { + dialog.SelectedPath = _txtDefaultTemplatePath.Text; + } + + if (dialog.ShowDialog(this) == DialogResult.OK) + { + _txtDefaultTemplatePath.Text = dialog.SelectedPath; + } + } + } + private void OnOpenParamCatalog() { try @@ -171,34 +229,36 @@ namespace CadParamPluging.UI private TabPage BuildEditableTab(string title, ListBox listBox) { var page = new TabPage(title); + page.Padding = new Padding(8); + page.UseVisualStyleBackColor = true; var layout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 1, - Padding = new Padding(8) }; layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f)); - layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100f)); // Fixed width for button column listBox.Dock = DockStyle.Fill; + listBox.IntegralHeight = false; // smoother resizing var actions = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.TopDown, WrapContents = false, - AutoSize = true + Padding = new Padding(4, 0, 0, 0) }; - var btnAdd = new Button { Text = "新增", AutoSize = true }; + var btnAdd = new Button { Text = "新增", Width = 90, Height = 30 }; btnAdd.Click += (_, __) => OnAddItem(title, listBox); - var btnEdit = new Button { Text = "修改", AutoSize = true }; + var btnEdit = new Button { Text = "修改", Width = 90, Height = 30 }; btnEdit.Click += (_, __) => OnEditItem(title, listBox); - var btnDelete = new Button { Text = "删除", AutoSize = true }; + var btnDelete = new Button { Text = "删除", Width = 90, Height = 30 }; btnDelete.Click += (_, __) => OnDeleteItem(title, listBox); actions.Controls.Add(btnAdd); @@ -291,7 +351,8 @@ namespace CadParamPluging.UI DeliveryStatuses = _lbDeliveryStatuses.Items.Cast().Select(o => (o as string) ?? string.Empty).ToList(), ProcessMethods = _lbProcessMethods.Items.Cast().Select(o => (o as string) ?? string.Empty).ToList(), StructuralFeatures = _lbStructuralFeatures.Items.Cast().Select(o => (o as string) ?? string.Empty).ToList(), - SpecialConditions = _lbSpecialConditions.Items.Cast().Select(o => (o as string) ?? string.Empty).ToList() + SpecialConditions = _lbSpecialConditions.Items.Cast().Select(o => (o as string) ?? string.Empty).ToList(), + DefaultTemplatePath = _txtDefaultTemplatePath.Text.Trim() }; result.Normalize(); diff --git a/UI/TemplateSelectionItem.cs b/UI/TemplateSelectionItem.cs new file mode 100644 index 0000000..afcc6af --- /dev/null +++ b/UI/TemplateSelectionItem.cs @@ -0,0 +1,30 @@ +using CadParamPluging.Domain.Models; + +namespace CadParamPluging.UI +{ + public class TemplateSelectionItem + { + public TemplateInfo Info { get; set; } + + public TemplateSelectionItem(TemplateInfo info) + { + Info = info; + } + + public override string ToString() + { + if (Info == null) + { + return "无效模板"; + } + + var sheet = !string.IsNullOrWhiteSpace(Info.LayoutName) + ? Info.LayoutName + : "Model"; + + return $"{Info.Name} - {sheet}"; + } + + public Autodesk.AutoCAD.DatabaseServices.Extents3d? ModelWindow { get; set; } + } +}