XAML WPF组合框- ItemTemplate与是否可编辑

j1dl9f46  于 2023-08-01  发布在  其他
关注(0)|答案(1)|浏览(137)

我用一个项目模板创建了一个组合框。模板包括状态图标和文本:
x1c 0d1x的数据
下面是XAML:

<DataTemplate x:Key="ItemTemplate">
      <WrapPanel>
        <Image Width="24" Height="24" Stretch="Fill" Source="{Binding StateImage}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,0,15,0"/>
        <Label Content="{Binding Address}" VerticalAlignment="Center" HorizontalAlignment="Center" />
      </WrapPanel>
    </DataTemplate>

<ComboBox x:Name="CbxClients" HorizontalAlignment="Center" VerticalAlignment="Top" ItemTemplate="{StaticResource ItemTemplate}" Width="320" Height="24" IsEditable="False" />

字符串
现在我想使组合框可编辑,这样用户就可以输入新的字符串,然后将其添加到列表中。因此,我将“IsEditable”设置为true。这就是结果:



此更改会导致一个问题:图标现在不再显示在组合框中(仅在下拉区域中)。在编辑/输入字符串时,这是可以的,但是在输入被提交之后,我希望新的项被添加到列表中,并且显示一个图标。
有什么方法可以实现这种行为吗?

2w2cym1i

2w2cym1i1#

您遇到了两个问题:
1.问题:ComboBox不包含简单的string项。相反,您定义了一个DataTemplate来呈现一个更复杂的项模型。

**解决方案:**关键是ComboBox没有机会知道如何使用输入值来构造item模型的新示例。你必须明确地这样做。

1.**问题:**因为您的ComboBox配置为编辑模式,所以TextBox将只包含项目模型的文本表示(ComboBox将在模型上调用object.ToString以获取文本表示)。

**解决方案:**没有现成的解决方案。如果ComboBox.IsEditable返回false,则ComboBox将使用ContentPresenter显示ComboBox.SelectedItem。如果ComboBox.IsEditable返回true,则ComboBox将用TextBox替换ContentPresenter以允许编辑。您现在可以覆盖原始的ControlTemplate并在两个内容站点之间切换。例如,在GotFocus上显示TextBox,在LostFocus上切换回ContentPresenter

您可以使用XAML设计器来提取ControlTemplate或使用visit Microsoft Dos: ComboBox Styles and Templates并从那里复制模板和引用。
要启用文本搜索,请将ComboBox.IsTextSearchEnabled设置为true,并将附加属性TextSearch.TextPath设置为项目模型上的实际属性。
出于性能原因,您应该将Label替换为TextBlock,特别是当显示的文本是动态的时。
以下是项目模型:

class NetworkAddress : INotifyPropertyChanged
{
  public ImageSource StateImage { get; set; }
  public string Address { get; set; }
}

字符串
要启用搜索和项目创建,您必须按以下方式配置ComboBox

<ComboBox ItemsSource="{Binding NetworkAddresses}"
          IsEditable="True"
          IsTextSearchEnabled="True"
          TextSearch.TextPath="Address"
          PreviewKeyUp="ComboBox_PreviewKeyUp">
  <ComboBox.ItemTemplate>
    <DataTemplate DataType="{x:Type NetworkAddress}">
      <WrapPanel>
        <Image Source="{Binding StateImage}" />
        <TextBlock Text="{Binding Address}" />
      </WrapPanel>
    </DataTemplate>
  </ComboBox.ItemTemplate>
</ComboBox>


然后处理ComboBox.PreviewKeyUp事件以添加新项:

partial class MainWindow : Window
{
  // TODO::Property must be a dependency property because MainWindow is a DependencyObject
  public ObservableCollection<NetworkAddress> NetworkAddresses { get; }

  public MainWindow()
  {
    InitializeComponent();

    this.DataContext = this;
    this.NetworkAddresses = new ObservableCollection<NetworkAddress>
    {
      new NetworkAddress() { ... },
      new NetworkAddress() { ... },
    };
  }

  private void ComboBox_PreviewKeyUp(object sender, KeyEventArgs e)
  {
    if (e.Key is not Key.Enter or not Key.Return)
    {
      return;
    }

    var comboBox = sender as ComboBox;
    string inputText = comboBox.Text;
    if (comboBox.IsTextSearchEnabled
        && comboBox.SelectedItem is null
      || !this.NetworkAddresse.Any(address => address.Address.Equals(inputText, StringComparison.OrdinalIgnoreCase)))
    {
      AddNewItemToCollection(inputText);;
      comboBox.SelectedIndex = comboBox.Items.Count - 1;

      // Refresh is only required for the ComboBox flyout to render properly
      comboBox.Items.Refresh();
    }
  }

  private void AddNewItemToCollection(string text) 
    => this.NetworksAddresses.Add(new NetworkAddress() { ... });

相关问题