feat: implement part type management and searchable combo box in property editor

This commit is contained in:
Ling 2026-04-09 17:06:29 +08:00
parent f13d646f7d
commit 0d55a38c86
6 changed files with 255 additions and 16 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"dotnet.preferCSharpExtension": true
}

92
Common/PLMService.cs Normal file
View File

@ -0,0 +1,92 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace Laservall.Solidworks.Common
{
public class PartTypeItem
{
[JsonProperty("type_id")]
public string TypeId { get; set; }
[JsonProperty("parent_type_id")]
public string ParentTypeId { get; set; }
[JsonProperty("code")]
public string Code { get; set; }
[JsonProperty("type_name")]
public string TypeName { get; set; }
[JsonProperty("type_key")]
public string TypeKey { get; set; }
[JsonProperty("is_child")]
public string IsChild { get; set; }
public string DisplayText => $"{Code} - {TypeName}";
public override string ToString() => DisplayText;
}
public static class PLMService
{
private const string PartTypeSearchUrl = "http://10.0.0.155:9992/api/PLM/PartType/Search";
private static readonly HttpClient _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
private static List<PartTypeItem> _cachedPartTypes;
private static readonly object _lock = new object();
public static List<PartTypeItem> CachedPartTypes
{
get
{
lock (_lock)
{
return _cachedPartTypes ?? new List<PartTypeItem>();
}
}
}
public static async Task<List<PartTypeItem>> SearchPartTypesAsync(string code = "", string name = "")
{
try
{
var requestBody = new { code = code ?? "", name = name ?? "" };
var json = JsonConvert.SerializeObject(requestBody);
var content = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
var response = await _httpClient.PostAsync(PartTypeSearchUrl, content).ConfigureAwait(false);
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
Debug.WriteLine($"PLM PartType/Search failed: {(int)response.StatusCode} {responseText}");
return new List<PartTypeItem>();
}
return JsonConvert.DeserializeObject<List<PartTypeItem>>(responseText)
?? new List<PartTypeItem>();
}
catch (Exception ex)
{
Debug.WriteLine($"PLM PartType/Search error: {ex.Message}");
return new List<PartTypeItem>();
}
}
public static async Task LoadAndCachePartTypesAsync()
{
var items = await SearchPartTypesAsync("", "").ConfigureAwait(false);
lock (_lock)
{
_cachedPartTypes = items;
}
Debug.WriteLine($"PLM PartTypes loaded: {items.Count} items");
}
}
}

View File

@ -1,10 +1,10 @@
using HandyControl.Controls; using HandyControl.Controls;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Laservall.Solidworks.Common namespace Laservall.Solidworks.Common
{ {
@ -35,7 +35,7 @@ namespace Laservall.Solidworks.Common
{ {
public override FrameworkElement CreateElement(PropertyItem propertyItem) public override FrameworkElement CreateElement(PropertyItem propertyItem)
{ {
var comboBox = new ComboBox(); var comboBox = new System.Windows.Controls.ComboBox();
comboBox.IsEditable = true; comboBox.IsEditable = true;
var items = ComboBoxDataRegistry.GetItems(propertyItem.DisplayName); var items = ComboBoxDataRegistry.GetItems(propertyItem.DisplayName);
comboBox.ItemsSource = items; comboBox.ItemsSource = items;
@ -49,29 +49,109 @@ namespace Laservall.Solidworks.Common
public override DependencyProperty GetDependencyProperty() public override DependencyProperty GetDependencyProperty()
{ {
return ComboBox.SelectedItemProperty; return System.Windows.Controls.ComboBox.SelectedItemProperty;
} }
} }
public class CategoryComboxPropertyEditor : PropertyEditorBase public class CategoryComboxPropertyEditor : PropertyEditorBase
{ {
private static List<PartTypeItem> _allPartTypes = new List<PartTypeItem>();
public static void SetPartTypes(List<PartTypeItem> items)
{
_allPartTypes = items ?? new List<PartTypeItem>();
}
public override FrameworkElement CreateElement(PropertyItem propertyItem) public override FrameworkElement CreateElement(PropertyItem propertyItem)
{ {
var comboBox = new ComboBox(); var comboBox = new System.Windows.Controls.ComboBox
comboBox.IsEditable = true; {
var items = ComboBoxDataRegistry.GetItems(propertyItem.DisplayName); IsEditable = true,
comboBox.ItemsSource = items; IsTextSearchEnabled = false
comboBox.SelectedItem = propertyItem.Value?.ToString(); };
var allItems = _allPartTypes;
comboBox.ItemsSource = allItems;
comboBox.DisplayMemberPath = "DisplayText";
comboBox.SelectedValuePath = "Code";
var currentCode = propertyItem.Value?.ToString();
if (!string.IsNullOrEmpty(currentCode))
{
var match = allItems.FirstOrDefault(x =>
string.Equals(x.Code, currentCode, StringComparison.OrdinalIgnoreCase));
if (match != null)
{
comboBox.SelectedItem = match;
}
}
bool suppressFilter = false;
comboBox.SelectionChanged += (s, e) => comboBox.SelectionChanged += (s, e) =>
{ {
propertyItem.Value = comboBox.SelectedItem; if (comboBox.SelectedItem is PartTypeItem selected)
{
propertyItem.Value = selected.Code;
}
}; };
comboBox.Loaded += (s, e) =>
{
var textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;
if (textBox == null) return;
textBox.TextChanged += (s2, e2) =>
{
if (suppressFilter) return;
var text = textBox.Text;
if (string.IsNullOrEmpty(text))
{
comboBox.ItemsSource = allItems;
}
else
{
var lower = text.ToLowerInvariant();
var filtered = allItems.Where(x =>
(x.Code != null && x.Code.ToLowerInvariant().Contains(lower)) ||
(x.TypeName != null && x.TypeName.ToLowerInvariant().Contains(lower))
).ToList();
comboBox.ItemsSource = filtered;
}
suppressFilter = true;
comboBox.IsDropDownOpen = true;
textBox.Text = text;
textBox.CaretIndex = text.Length;
suppressFilter = false;
};
};
comboBox.DropDownClosed += (s, e) =>
{
if (comboBox.SelectedItem is PartTypeItem selected)
{
suppressFilter = true;
var textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;
if (textBox != null)
{
textBox.Text = selected.DisplayText;
textBox.CaretIndex = textBox.Text.Length;
}
suppressFilter = false;
comboBox.ItemsSource = allItems;
}
};
return comboBox; return comboBox;
} }
public override DependencyProperty GetDependencyProperty() public override DependencyProperty GetDependencyProperty()
{ {
return ComboBox.SelectedItemProperty; return System.Windows.Controls.ComboBox.SelectedValueProperty;
} }
} }

View File

@ -89,6 +89,7 @@
<Compile Include="AppDomainDllLoader.cs" /> <Compile Include="AppDomainDllLoader.cs" />
<Compile Include="Common\PLMConfig.cs" /> <Compile Include="Common\PLMConfig.cs" />
<Compile Include="Common\PropertyEditor.cs" /> <Compile Include="Common\PropertyEditor.cs" />
<Compile Include="Common\PartTypeService.cs" />
<Compile Include="Common\SM4Helper.cs" /> <Compile Include="Common\SM4Helper.cs" />
<Compile Include="Common\ViewModelBase.cs" /> <Compile Include="Common\ViewModelBase.cs" />
<Compile Include="Common\RelayCommand.cs" /> <Compile Include="Common\RelayCommand.cs" />
@ -169,7 +170,7 @@
<Import Project="packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets" Condition="Exists('packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets')" /> <Import Project="packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets" Condition="Exists('packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText> <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用"NuGet 程序包还原"可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets'))" /> <Error Condition="!Exists('packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Xarial.XCad.SolidWorks.0.8.2\build\Xarial.XCad.SolidWorks.targets'))" />
</Target> </Target>

View File

@ -1,4 +1,4 @@
using HandyControl.Controls; using HandyControl.Controls;
using Laservall.Solidworks.Common; using Laservall.Solidworks.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -168,6 +168,21 @@ namespace Laservall.Solidworks.Model
} }
} }
private string _partType;
[Category("零件属性")]
[DisplayName("零件类型")]
[Editor(typeof(SearchableComboBoxPropertyEditor), typeof(SearchableComboBoxPropertyEditor))]
public string PartType
{
get => _partType;
set
{
if (_partType == value) return;
_partType = value;
OnPropertyChanged();
}
}
private bool _purCheck; private bool _purCheck;
[Category("零件属性")] [Category("零件属性")]
[DisplayName("采购检验")] [DisplayName("采购检验")]

View File

@ -4,6 +4,7 @@ using Laservall.Solidworks.Model;
using SolidWorks.Interop.sldworks; using SolidWorks.Interop.sldworks;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using Xarial.XCad; using Xarial.XCad;
using Xarial.XCad.Documents; using Xarial.XCad.Documents;
@ -37,8 +38,16 @@ namespace Laservall.Solidworks.Pane
set => Set(ref _versionText, value); set => Set(ref _versionText, value);
} }
private bool _isLoadingPartTypes;
public bool IsLoadingPartTypes
{
get => _isLoadingPartTypes;
set => Set(ref _isLoadingPartTypes, value);
}
public ICommand SaveCommand { get; } public ICommand SaveCommand { get; }
public ICommand ResetCommand { get; } public ICommand ResetCommand { get; }
public ICommand RefreshPartTypesCommand { get; }
public PartPropPaneViewModel() public PartPropPaneViewModel()
{ {
@ -46,6 +55,45 @@ namespace Laservall.Solidworks.Pane
SaveCommand = new RelayCommand(ExecuteSave, CanSave); SaveCommand = new RelayCommand(ExecuteSave, CanSave);
ResetCommand = new RelayCommand(ExecuteReset, CanReset); ResetCommand = new RelayCommand(ExecuteReset, CanReset);
RefreshPartTypesCommand = new RelayCommand(async _ => await LoadPartTypesAsync());
// 异步加载零件类型数据
Task.Run(async () => await LoadPartTypesAsync());
}
/// <summary>
/// 从PLM API加载零件类型数据
/// </summary>
private async Task LoadPartTypesAsync()
{
try
{
IsLoadingPartTypes = true;
StatusText = "正在加载零件类型...";
// 调用PLM API获取零件类型
var partTypes = await PartTypeService.GetAllAsync();
if (partTypes.Count > 0)
{
// 注册到可搜索ComboBox编辑器
SearchableComboBoxPropertyEditor.RegisterPartTypes("零件类型", partTypes);
StatusText = $"已加载 {partTypes.Count} 个零件类型";
}
else
{
StatusText = "未找到零件类型数据";
}
}
catch (System.Exception ex)
{
Debug.WriteLine($"加载零件类型失败: {ex.Message}");
StatusText = "加载零件类型失败";
}
finally
{
IsLoadingPartTypes = false;
}
} }
public void OnSelectionChanged(IXDocument doc, IXSelObject selObject) public void OnSelectionChanged(IXDocument doc, IXSelObject selObject)