v2.2: 桌面版同步 DESTACO 风格选型 + 网页预览后台启动
桌面版 (仅网页版 v2.1 已做的部分, 本次补齐桌面端, 两端语义一致) - 新增 OptionTile 控件类: 三态选项块 (可选/已选/不可选), 替代 ComboBox 下拉 不可选取值置灰+删除线但保留占位 (让用户看到选项存在, 而非从列表消失); 悬停青色高亮, 再点一次取消选择 - 新增零件号实时条: 复用与网页版同一套「候选型号最长公共前缀」算法, 已确定片段深青实心 + 待定位数虚化 + 进度条, 选满唯一命中时整块转青色实心 - 维度标题后回显当前已选值 - range 参数 (连续域) 保留可编辑下拉, 无法枚举成卡片 - 参数联动仍复用 Configurator.AllowedOptions, 规则引擎未改动 网页预览后台启动 (无 PowerShell 窗口) - 新增 tools/serve-web-bg.ps1: Start-Process -WindowStyle Hidden 启动, 带 -Stop / -Status; 用命令行匹配定位进程 (比只看 PID 文件可靠) - _start_web.bat / _start_all.bat 改用之, 不再弹窗口 工具 - ui-diagnose.ps1 增强: 原只检查 _boxes (下拉), 现同时检查选项块数量、 每维度是否有可选值、零件号条输出 —— 可自动发现"某维度全被置灰无从下手" - 新增 assess-combo-risk.py: 用量化口径评估生成候选的风险 (以同缸径真实数据值域为官方值域的代理) - 新增 make-pending-list.py: 重写待补清单, 增加 nearest_real / diff_from_nearest 列, 每个候选与其最近的真实型号并列, 便于逐个核实 文档 - 新增 工作总结-2026-09.md: 两阶段工作回顾、发现的问题、踩坑经验 验证 - 编译首次通过; UI 诊断 40/40 系列 0 问题 - 零件号条实测: KC0032-10 / ULP32020AEK0 / UAGP075OK120WS0 / LAE140NN31 均完整; UCBP 正确提示"该组合对应 2 个型号" (暴露已知数据问题) 踩坑记录 - PowerShell 变量名大小写不敏感: $root 与 $Root 是同一变量, 互相覆盖导致 启动脚本指向错误目录 (改用 $projRoot) - .ps1 必须带 UTF-8 BOM, 否则 PS 5.1 按 ANSI 读, 中文注释破坏解析 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,118 @@ namespace Ounibo.Catalog.App
|
||||
public override string ToString() { return Text; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选项块 (DESTACO 风, 2026-09-15): 替代下拉菜单的单值可选卡片。
|
||||
/// 三态: 可选 / 已选 / 不可选 (置灰划线但保留占位, 让用户看到选项存在)。
|
||||
/// </summary>
|
||||
public class OptionTile : Border
|
||||
{
|
||||
public object Value;
|
||||
public ParameterDef Param;
|
||||
readonly TextBlock _code;
|
||||
readonly TextBlock _desc;
|
||||
bool _usable = true, _on;
|
||||
|
||||
static readonly Brush BorderIdle = new SolidColorBrush(Color.FromRgb(0xE5, 0xE7, 0xEB));
|
||||
static readonly Brush BorderHover = new SolidColorBrush(Color.FromRgb(0x2D, 0xD4, 0xBF));
|
||||
static readonly Brush BorderOn = new SolidColorBrush(Color.FromRgb(0x14, 0xB8, 0xA6));
|
||||
static readonly Brush BgIdle = Brushes.White;
|
||||
static readonly Brush BgHover = new SolidColorBrush(Color.FromRgb(0xF0, 0xFD, 0xFA));
|
||||
static readonly Brush BgOn = new SolidColorBrush(Color.FromRgb(0xF0, 0xFD, 0xFA));
|
||||
static readonly Brush BgOff = new SolidColorBrush(Color.FromRgb(0xF9, 0xFA, 0xFB));
|
||||
static readonly Brush FgCodeIdle = new SolidColorBrush(Color.FromRgb(0x11, 0x18, 0x27));
|
||||
static readonly Brush FgCodeOn = new SolidColorBrush(Color.FromRgb(0x0F, 0x76, 0x6E));
|
||||
|
||||
public OptionTile(ParameterDef p, object value, string code, string desc, Action<OptionTile> onClick)
|
||||
{
|
||||
Param = p; Value = value;
|
||||
BorderThickness = new Thickness(1.5);
|
||||
CornerRadius = new CornerRadius(10);
|
||||
Padding = new Thickness(9, 7, 9, 7);
|
||||
Margin = new Thickness(0, 0, 6, 6);
|
||||
MinWidth = 58;
|
||||
Cursor = Cursors.Hand;
|
||||
Background = BgIdle;
|
||||
BorderBrush = BorderIdle;
|
||||
|
||||
var sp = new StackPanel { HorizontalAlignment = HorizontalAlignment.Center };
|
||||
_code = new TextBlock
|
||||
{
|
||||
Text = code,
|
||||
FontFamily = new FontFamily("Consolas, monospace"),
|
||||
FontWeight = FontWeights.Bold,
|
||||
FontSize = 13,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
TextAlignment = TextAlignment.Center
|
||||
};
|
||||
sp.Children.Add(_code);
|
||||
if (!string.IsNullOrEmpty(desc) && desc != code)
|
||||
{
|
||||
_desc = new TextBlock
|
||||
{
|
||||
Text = desc,
|
||||
FontSize = 10,
|
||||
Margin = new Thickness(0, 2, 0, 0),
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
TextAlignment = TextAlignment.Center,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
MaxWidth = 120,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x9C, 0xA3, 0xAF))
|
||||
};
|
||||
sp.Children.Add(_desc);
|
||||
}
|
||||
Child = sp;
|
||||
|
||||
MouseEnter += (s, e) => { if (_usable && !_on) { BorderBrush = BorderHover; Background = BgHover; } };
|
||||
MouseLeave += (s, e) => { if (_usable && !_on) { BorderBrush = BorderIdle; Background = BgIdle; } };
|
||||
MouseLeftButtonUp += (s, e) => { if (_usable) onClick(this); };
|
||||
}
|
||||
|
||||
/// <summary>设置可用性 (被联动规则排除时置灰但不移除)。</summary>
|
||||
public void SetUsable(bool usable)
|
||||
{
|
||||
_usable = usable;
|
||||
Cursor = usable ? Cursors.Hand : Cursors.Arrow;
|
||||
if (!usable)
|
||||
{
|
||||
Background = BgOff; BorderBrush = BorderIdle;
|
||||
BorderThickness = new Thickness(1.5);
|
||||
_code.Foreground = new SolidColorBrush(Color.FromRgb(0x9C, 0xA3, 0xAF));
|
||||
_code.TextDecorations = TextDecorations.Strikethrough;
|
||||
Opacity = 0.4;
|
||||
if (_desc != null) _desc.Opacity = 0.7;
|
||||
}
|
||||
else
|
||||
{
|
||||
Opacity = 1;
|
||||
_code.TextDecorations = null;
|
||||
if (_desc != null) _desc.Opacity = 1;
|
||||
ApplyState();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>设置选中态。</summary>
|
||||
public void SetOn(bool on)
|
||||
{
|
||||
_on = on;
|
||||
if (_usable) ApplyState();
|
||||
}
|
||||
|
||||
void ApplyState()
|
||||
{
|
||||
if (_on)
|
||||
{
|
||||
Background = BgOn; BorderBrush = BorderOn;
|
||||
_code.Foreground = FgCodeOn;
|
||||
}
|
||||
else
|
||||
{
|
||||
Background = BgIdle; BorderBrush = BorderIdle;
|
||||
_code.Foreground = FgCodeIdle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主窗口: 目录树 + 参数选型 + 3D 预览 + 尺寸图/参数表/数据表 + 搜索 + STEP 下载/批量下载。
|
||||
/// </summary>
|
||||
@@ -48,6 +160,12 @@ namespace Ounibo.Catalog.App
|
||||
Series _series;
|
||||
readonly Dictionary<string, object> _sel = new Dictionary<string, object>();
|
||||
readonly Dictionary<string, ComboBox> _boxes = new Dictionary<string, ComboBox>();
|
||||
// 选项块 (DESTACO 风, 2026-09-15): 每个参数一组可点选项块, 替代下拉菜单
|
||||
readonly Dictionary<string, List<OptionTile>> _tiles = new Dictionary<string, List<OptionTile>>();
|
||||
readonly Dictionary<string, WrapPanel> _tilePanels = new Dictionary<string, WrapPanel>();
|
||||
TextBlock _skuCode, _skuHint; // 零件号实时条
|
||||
Border _skuBar;
|
||||
ProgressBar _skuProg;
|
||||
readonly Dictionary<string, double?[]> _ranges = new Dictionary<string, double?[]>();
|
||||
readonly Dictionary<string, TextBox[]> _rangeBoxes = new Dictionary<string, TextBox[]>();
|
||||
List<SearchEngine.SearchItem> _searchResult;
|
||||
@@ -165,6 +283,53 @@ namespace Ounibo.Catalog.App
|
||||
var left = new StackPanel { Margin = new Thickness(8) };
|
||||
_modelTitle = new TextBlock { FontSize = 16, FontWeight = FontWeights.Bold, Margin = new Thickness(0, 0, 0, 8), TextWrapping = TextWrapping.Wrap };
|
||||
left.Children.Add(_modelTitle);
|
||||
|
||||
// 零件号实时条 (DESTACO 风, 2026-09-15): 边选边拼, 已确定片段高亮 / 待定虚化
|
||||
_skuBar = new Border
|
||||
{
|
||||
CornerRadius = new CornerRadius(12),
|
||||
BorderThickness = new Thickness(1),
|
||||
BorderBrush = new SolidColorBrush(Color.FromRgb(0x99, 0xF6, 0xE4)),
|
||||
Background = new LinearGradientBrush(
|
||||
Color.FromRgb(0xF0, 0xFD, 0xFA), Colors.White, 45),
|
||||
Padding = new Thickness(12, 10, 12, 10),
|
||||
Margin = new Thickness(0, 0, 0, 10)
|
||||
};
|
||||
var skuInner = new StackPanel();
|
||||
skuInner.Children.Add(new TextBlock
|
||||
{
|
||||
Text = _lang.T("零件号 Part Number", "Part Number"),
|
||||
FontSize = 10,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x9C, 0xA3, 0xAF)),
|
||||
Margin = new Thickness(0, 0, 0, 4)
|
||||
});
|
||||
_skuCode = new TextBlock
|
||||
{
|
||||
FontFamily = new FontFamily("Consolas, monospace"),
|
||||
FontSize = 17, FontWeight = FontWeights.Bold,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
MinHeight = 22
|
||||
};
|
||||
skuInner.Children.Add(_skuCode);
|
||||
_skuProg = new ProgressBar
|
||||
{
|
||||
Height = 3, Margin = new Thickness(0, 7, 0, 0),
|
||||
Minimum = 0, Maximum = 1, Value = 0,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x14, 0xB8, 0xA6)),
|
||||
Background = new SolidColorBrush(Color.FromRgb(0xCC, 0xFB, 0xF1)),
|
||||
BorderThickness = new Thickness(0)
|
||||
};
|
||||
skuInner.Children.Add(_skuProg);
|
||||
_skuHint = new TextBlock
|
||||
{
|
||||
FontSize = 11, Margin = new Thickness(0, 6, 0, 0),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x6B, 0x72, 0x80))
|
||||
};
|
||||
skuInner.Children.Add(_skuHint);
|
||||
_skuBar.Child = skuInner;
|
||||
left.Children.Add(_skuBar);
|
||||
|
||||
_paramPanel = new StackPanel();
|
||||
left.Children.Add(_paramPanel); // 参数最多 7 行, 直接平铺不滚动 (避免下方参数被遮挡)
|
||||
// 下载操作区 (2026-08-24, 与网页版一致: 参数下方并排 下载 STEP / 下载 PDF, 同款配色)
|
||||
@@ -494,6 +659,8 @@ namespace Ounibo.Catalog.App
|
||||
_series = null; _cfg = null;
|
||||
_paramPanel.Children.Clear();
|
||||
_boxes.Clear(); _sel.Clear();
|
||||
_tiles.Clear(); _tilePanels.Clear();
|
||||
if (_skuBar != null) _skuBar.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
void TreeSelected(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||
@@ -512,26 +679,67 @@ namespace Ounibo.Catalog.App
|
||||
_cfg = new Configurator(s);
|
||||
_sel.Clear();
|
||||
_boxes.Clear();
|
||||
_tiles.Clear();
|
||||
_tilePanels.Clear();
|
||||
_paramPanel.Children.Clear();
|
||||
_ranges.Clear(); _rangeBoxes.Clear(); _rangePanel.Children.Clear();
|
||||
if (_skuBar != null) _skuBar.Visibility = Visibility.Visible;
|
||||
|
||||
foreach (var p in s.parameters)
|
||||
{
|
||||
var row = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 0, 0, 8) };
|
||||
row.Children.Add(new TextBlock { Text = ParamLabel(p), Width = 120, VerticalAlignment = VerticalAlignment.Center });
|
||||
var cb = new ComboBox { Width = 150, Tag = p };
|
||||
var block = new StackPanel { Margin = new Thickness(0, 0, 0, 10) };
|
||||
// 维度标题: 小号大写 + 已选值回显
|
||||
var head = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 0, 0, 5) };
|
||||
head.Children.Add(new TextBlock
|
||||
{
|
||||
Text = ParamLabel(p).ToUpperInvariant(),
|
||||
FontSize = 10.5, FontWeight = FontWeights.Bold,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x9C, 0xA3, 0xAF)),
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
});
|
||||
var picked = new TextBlock
|
||||
{
|
||||
FontSize = 11.5, FontWeight = FontWeights.SemiBold,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x0F, 0x76, 0x6E)),
|
||||
Margin = new Thickness(7, 0, 0, 0),
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
picked.Tag = p.code; // 供 RefreshOptions 回显
|
||||
head.Children.Add(picked);
|
||||
block.Children.Add(head);
|
||||
|
||||
if (p.type == "range")
|
||||
{
|
||||
// 参数化 range 域: 可编辑下拉 (标准档位快捷选 + 自由输入, 与网页版一致)
|
||||
cb.IsEditable = true;
|
||||
cb.IsTextSearchEnabled = false;
|
||||
// 连续域无法枚举成选项块 → 保留可编辑下拉 (标准档位 + 自由输入)
|
||||
var cb = new ComboBox { Width = 150, Tag = p, IsEditable = true, IsTextSearchEnabled = false, HorizontalAlignment = HorizontalAlignment.Left };
|
||||
cb.KeyDown += (s2, e2) => { if (e2.Key == System.Windows.Input.Key.Enter) TrySetRangeText(cb); };
|
||||
cb.LostKeyboardFocus += (s2, e2) => TrySetRangeText(cb);
|
||||
cb.SelectionChanged += ParamChanged;
|
||||
block.Children.Add(cb);
|
||||
_boxes[p.code] = cb;
|
||||
}
|
||||
cb.SelectionChanged += ParamChanged;
|
||||
row.Children.Add(cb);
|
||||
_paramPanel.Children.Add(row);
|
||||
_boxes[p.code] = cb;
|
||||
else
|
||||
{
|
||||
// 枚举维度 → 选项块网格 (有说明显示说明, 无说明只显示代号)
|
||||
var wrap = new WrapPanel();
|
||||
var list = new List<OptionTile>();
|
||||
foreach (var v in (p.values ?? new List<object>()))
|
||||
{
|
||||
var key = v == null ? "" : Convert.ToString(v, CultureInfo.InvariantCulture);
|
||||
var disp = DisplayText(p, v);
|
||||
bool hasDesc = !string.IsNullOrEmpty(disp) && disp != key;
|
||||
var tile = new OptionTile(p, v,
|
||||
hasDesc ? (key.Length == 0 ? "—" : key) : disp,
|
||||
hasDesc ? disp : null,
|
||||
OnTileClick);
|
||||
list.Add(tile);
|
||||
wrap.Children.Add(tile);
|
||||
}
|
||||
block.Children.Add(wrap);
|
||||
_tilePanels[p.code] = wrap;
|
||||
_tiles[p.code] = list;
|
||||
}
|
||||
_paramPanel.Children.Add(block);
|
||||
|
||||
// 数值/range 参数 → 参数表范围筛选控件
|
||||
if (p.type == "number" || p.type == "range")
|
||||
@@ -598,6 +806,116 @@ namespace Ounibo.Catalog.App
|
||||
RefreshOptions();
|
||||
}
|
||||
|
||||
/// <summary>选项块点击: 切换选择 (再点一次取消); 与下拉时代语义一致。</summary>
|
||||
void OnTileClick(OptionTile tile)
|
||||
{
|
||||
if (_refreshing || _cfg == null) return;
|
||||
var code = tile.Param.code;
|
||||
if (_sel.ContainsKey(code) && EqStr(_sel[code], tile.Value)) _sel.Remove(code);
|
||||
else _sel[code] = tile.Value;
|
||||
RefreshOptions();
|
||||
}
|
||||
|
||||
// ---------- 零件号实时拼装 (DESTACO 风, 与网页版同一套语义) ----------
|
||||
// 不依赖编码模板 (40 系列仅 KC 有): 用「当前候选型号的最长公共前缀」——
|
||||
// 选得越多候选越少、前缀越长, 逐字拼出完整零件号。
|
||||
List<string> CandidateCodes()
|
||||
{
|
||||
var res = new List<string>();
|
||||
if (_series == null) return res;
|
||||
var vs = _series.variants ?? new List<Variant>();
|
||||
if (_sel.Count == 0) { foreach (var v in vs) res.Add(v.modelCode); return res; }
|
||||
foreach (var v in vs)
|
||||
{
|
||||
bool ok = true;
|
||||
foreach (var kv in _sel)
|
||||
{
|
||||
object val;
|
||||
if (!v.@params.TryGetValue(kv.Key, out val) || !EqStr(val, kv.Value)) { ok = false; break; }
|
||||
}
|
||||
if (ok) res.Add(v.modelCode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static string LongestCommonPrefix(List<string> list)
|
||||
{
|
||||
if (list == null || list.Count == 0) return "";
|
||||
var a = list[0]; var b = list[0];
|
||||
foreach (var x in list)
|
||||
{
|
||||
if (string.CompareOrdinal(x, a) < 0) a = x;
|
||||
if (string.CompareOrdinal(x, b) > 0) b = x;
|
||||
}
|
||||
int i = 0;
|
||||
while (i < a.Length && i < b.Length && a[i] == b[i]) i++;
|
||||
return a.Substring(0, i);
|
||||
}
|
||||
|
||||
/// <summary>刷新零件号实时条: 已确定前缀 + 待定位数 + 进度 + 提示。</summary>
|
||||
void RefreshSkuBar()
|
||||
{
|
||||
if (_skuBar == null || _series == null) return;
|
||||
var total = (_series.parameters ?? new List<ParameterDef>()).Count;
|
||||
var chosen = _sel.Count;
|
||||
var cand = CandidateCodes();
|
||||
var pre = LongestCommonPrefix(cand);
|
||||
|
||||
_skuCode.Inlines.Clear();
|
||||
if (pre.Length > 0)
|
||||
{
|
||||
_skuCode.Inlines.Add(new System.Windows.Documents.Run(pre)
|
||||
{
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0x0F, 0x76, 0x6E))
|
||||
});
|
||||
}
|
||||
var rest = new string('·', Math.Max(0, total - chosen));
|
||||
if (rest.Length > 0)
|
||||
{
|
||||
_skuCode.Inlines.Add(new System.Windows.Documents.Run(rest)
|
||||
{
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0xD1, 0xD5, 0xDB))
|
||||
});
|
||||
}
|
||||
if (pre.Length == 0 && rest.Length == 0)
|
||||
{
|
||||
_skuCode.Inlines.Add(new System.Windows.Documents.Run(
|
||||
_lang.T("选择参数以生成零件号", "Select options to build part number"))
|
||||
{ Foreground = new SolidColorBrush(Color.FromRgb(0xD1, 0xD5, 0xDB)) });
|
||||
}
|
||||
|
||||
bool done = chosen == total && cand.Count == 1;
|
||||
if (done)
|
||||
{
|
||||
// 完成态: 整块转青色实心
|
||||
_skuBar.Background = new LinearGradientBrush(
|
||||
Color.FromRgb(0x14, 0xB8, 0xA6), Color.FromRgb(0x0D, 0x94, 0x88), 45);
|
||||
_skuBar.BorderBrush = Brushes.Transparent;
|
||||
_skuCode.Inlines.Clear();
|
||||
_skuCode.Inlines.Add(new System.Windows.Documents.Run(pre) { Foreground = Brushes.White });
|
||||
}
|
||||
else
|
||||
{
|
||||
_skuBar.Background = new LinearGradientBrush(
|
||||
Color.FromRgb(0xF0, 0xFD, 0xFA), Colors.White, 45);
|
||||
_skuBar.BorderBrush = new SolidColorBrush(Color.FromRgb(0x99, 0xF6, 0xE4));
|
||||
}
|
||||
_skuProg.Value = total == 0 ? 0 : (double)chosen / total;
|
||||
|
||||
if (chosen < total)
|
||||
_skuHint.Text = _lang.T(
|
||||
"已选 " + chosen + "/" + total + " 项 · 候选 " + cand.Count + " 个型号",
|
||||
chosen + "/" + total + " selected · " + cand.Count + " candidates");
|
||||
else if (cand.Count == 1)
|
||||
_skuHint.Text = _lang.T("零件号完整", "Part number complete");
|
||||
else if (cand.Count > 1)
|
||||
_skuHint.Text = _lang.T(
|
||||
"该参数组合对应 " + cand.Count + " 个型号, 请在参数表中选择",
|
||||
cand.Count + " models share these options — pick one in the table");
|
||||
else
|
||||
_skuHint.Text = _lang.T("无匹配型号", "No matching model");
|
||||
}
|
||||
|
||||
// range 参数自由输入 (参数化引擎): 回车/失焦时校验并写入选择; 非法输入恢复原显示 (与网页版一致)
|
||||
void TrySetRangeText(ComboBox cb)
|
||||
{
|
||||
@@ -632,6 +950,7 @@ namespace Ounibo.Catalog.App
|
||||
try
|
||||
{
|
||||
var allowed = _cfg.AllowedOptions(_sel);
|
||||
// 下拉 (range 参数)
|
||||
foreach (var kv in _boxes)
|
||||
{
|
||||
var cb = kv.Value;
|
||||
@@ -649,11 +968,52 @@ namespace Ounibo.Catalog.App
|
||||
if (_sel.ContainsKey(p.code))
|
||||
cb.SelectedItem = cb.Items.OfType<ComboItem>().FirstOrDefault(x => EqStr(x.Value, _sel[p.code]));
|
||||
}
|
||||
// 选项块 (枚举参数): 不可选的置灰保留, 已选的打勾
|
||||
foreach (var kv in _tiles)
|
||||
{
|
||||
var code = kv.Key;
|
||||
List<object> list;
|
||||
if (!allowed.TryGetValue(code, out list)) list = new List<object>();
|
||||
if (_sel.ContainsKey(code) && !list.Any(x => EqStr(x, _sel[code])))
|
||||
_sel.Remove(code);
|
||||
foreach (var tile in kv.Value)
|
||||
{
|
||||
tile.SetUsable(list.Any(x => EqStr(x, tile.Value)));
|
||||
tile.SetOn(_sel.ContainsKey(code) && EqStr(_sel[code], tile.Value));
|
||||
}
|
||||
}
|
||||
// 维度标题后的已选值回显
|
||||
if (_series != null)
|
||||
foreach (var p in _series.parameters)
|
||||
{
|
||||
var found = FindPickedTextBlock(p.code);
|
||||
if (found != null)
|
||||
found.Text = _sel.ContainsKey(p.code) ? "· " + DisplayText(p, _sel[p.code]) : "";
|
||||
}
|
||||
RefreshSkuBar();
|
||||
TryUpdateSelection();
|
||||
}
|
||||
finally { _refreshing = false; }
|
||||
}
|
||||
|
||||
/// <summary>按 Tag (=参数 code) 找到维度标题后的回显 TextBlock。</summary>
|
||||
TextBlock FindPickedTextBlock(string code)
|
||||
{
|
||||
foreach (var child in _paramPanel.Children)
|
||||
{
|
||||
var block = child as StackPanel;
|
||||
if (block == null || block.Children.Count == 0) continue;
|
||||
var head = block.Children[0] as StackPanel;
|
||||
if (head == null) continue;
|
||||
foreach (var h in head.Children)
|
||||
{
|
||||
var tb = h as TextBlock;
|
||||
if (tb != null && tb.Tag as string == code) return tb;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool EqStr(object a, object b)
|
||||
{
|
||||
return string.Equals(
|
||||
|
||||
Reference in New Issue
Block a user