在NinjaTrader WPF Grid中实现枚举值下拉列表以填充TextBox的方案问询
在NinjaTrader WPF Grid中实现枚举值下拉列表以填充TextBox的方案问询
嘿,看起来你已经在NinjaTrader的WPF Grid里搭好了基础界面,现在就差给那个TextBox加上枚举值的下拉选择功能对吧?我给你两个实用的方案,全用C#实现,完全不用XAML或者网页相关的东西,贴合你的需求:
方案1:替换TextBox为ComboBox(最省心的原生方案)
WPF的ComboBox控件本身就支持下拉选择,完美匹配你的枚举值选择需求,而且实现起来非常简单,还能直接利用你枚举里的Display属性显示友好名称:
首先,记得先引用System.ComponentModel命名空间(因为要读取DisplayAttribute)。然后把你原来创建systemsLabelVal(TextBox)的代码替换成下面的ComboBox代码:
// 声明类成员变量 private ComboBox systemsComboBox; private MySystems systemsValue = MySystems.NotSet; // 假设你的变量初始值是NotSet // 替换原来的TextBox创建逻辑 this.systemsComboBox = new ComboBox { Height = 20.0, Width = 60.0, FontSize = 10.0, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center, SelectedValuePath = "Value", // 指定选中值对应枚举本身 DisplayMemberPath = "Key" // 指定显示的是友好名称 }; // 保持和原TextBox一致的样式 this.systemsComboBox.Foreground = Brushes.White; this.systemsComboBox.Background = Brushes.Transparent; this.systemsComboBox.BorderBrush = Brushes.Transparent; // 填充枚举值,同时读取Display属性的友好名称 var enumOptions = Enum.GetValues(typeof(MySystems)) .Cast<MySystems>() .Select(enumVal => new KeyValuePair<string, MySystems>( // 优先取Display的Name,没有的话用枚举本身的名称 enumVal.GetType().GetMember(enumVal.ToString())[0].GetCustomAttribute<DisplayAttribute>()?.Name ?? enumVal.ToString(), enumVal )) .ToList(); this.systemsComboBox.ItemsSource = enumOptions; // 设置默认选中项 this.systemsComboBox.SelectedValue = this.systemsValue; // 绑定选择变更事件,更新你的变量和按钮内容 this.systemsComboBox.SelectionChanged += (sender, e) => { if (this.systemsComboBox.SelectedValue is MySystems selectedSystem) { this.systemsValue = selectedSystem; // 同步更新按钮的显示内容 var selectedOption = enumOptions.First(opt => opt.Value == selectedSystem); this.Systemsbtn.Content = selectedOption.Key; this.Systemsbtn.Name = selectedOption.Key; } }; // 添加到Grid中 Grid.SetColumnSpan(this.systemsComboBox, 3); Grid.SetRow(this.systemsComboBox, 3); grid5.Children.Add(this.systemsComboBox);
这个方案的好处是完全利用WPF原生控件,不用自己处理弹窗的显示隐藏,稳定性和维护性都更好,而且用户体验也符合标准的下拉选择习惯。
方案2:给TextBox添加Popup下拉列表(坚持用TextBox的场景)
如果你一定要保留TextBox,只在选中时弹出下拉列表,那可以用WPF的Popup控件配合ListBox来实现:
同样先引用System.ComponentModel,然后修改你的代码如下:
// 声明类成员变量 private TextBox systemsLabelVal; private Popup systemsPopup; private ListBox systemsListBox; private MySystems systemsValue = MySystems.NotSet; // 原来的TextBox创建逻辑,加上焦点事件 this.systemsLabelVal = new TextBox { Text = GetEnumDisplayName(this.systemsValue), Height = 20.0, Width = 60.0, FontSize = 10.0, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center, Foreground = Brushes.White, Background = Brushes.Transparent, BorderBrush = Brushes.Transparent, TextAlignment = TextAlignment.Center }; this.systemsLabelVal.GotFocus += SystemsLabelVal_GotFocus; this.systemsLabelVal.PreviewKeyDown += this.TextBox_PreviewKeyDown; grid5.Children.Add(this.systemsLabelVal); // 初始化Popup和ListBox this.systemsPopup = new Popup { PlacementTarget = this.systemsLabelVal, Placement = PlacementMode.Bottom, // 弹窗显示在TextBox下方 AllowsTransparency = true, PopupAnimation = PopupAnimation.Fade }; this.systemsListBox = new ListBox { Width = this.systemsLabelVal.Width, Background = Brushes.Gray, Foreground = Brushes.White, BorderBrush = Brushes.DimGray }; // 填充枚举值 var enumItems = Enum.GetValues(typeof(MySystems)) .Cast<MySystems>() .Select(val => new { DisplayName = GetEnumDisplayName(val), Value = val }) .ToList(); this.systemsListBox.ItemsSource = enumItems; this.systemsListBox.DisplayMemberPath = "DisplayName"; // 绑定ListBox的选择事件 this.systemsListBox.SelectionChanged += SystemsListBox_SelectionChanged; // 处理鼠标点击,避免弹窗提前关闭 this.systemsListBox.MouseUp += (s, args) => { if (this.systemsListBox.SelectedItem != null) { this.systemsPopup.IsOpen = false; } }; this.systemsPopup.Child = this.systemsListBox; // 辅助方法:获取枚举的Display名称 private string GetEnumDisplayName(MySystems enumVal) { return enumVal.GetType().GetMember(enumVal.ToString())[0].GetCustomAttribute<DisplayAttribute>()?.Name ?? enumVal.ToString(); } // 事件处理方法 private void SystemsLabelVal_GotFocus(object sender, RoutedEventArgs e) { this.systemsPopup.IsOpen = true; // 让ListBox获得焦点,避免TextBox失去焦点后弹窗直接关闭 this.systemsListBox.Focus(); } private void SystemsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (this.systemsListBox.SelectedItem is dynamic selectedItem) { this.systemsValue = selectedItem.Value; this.systemsLabelVal.Text = selectedItem.DisplayName; // 同步更新按钮内容 this.Systemsbtn.Content = selectedItem.DisplayName; this.Systemsbtn.Name = selectedItem.DisplayName; } }
这个方案保留了TextBox的外观,只有在获取焦点时才弹出下拉列表,适合你想要保持原有界面样式的需求。
小提示
不管用哪个方案,都要确保你的枚举所在的命名空间被正确引用(using Profit_Bot_Enums;),另外如果你的systemsValue变量初始值不是NotSet,记得同步设置控件的默认选中项。
内容来源于stack exchange
相关产品推荐
相关产品推荐

