无法选择 wpf 列表框项目

Posted

技术标签:

【中文标题】无法选择 wpf 列表框项目【英文标题】:wpf listbox items cannot be selected 【发布时间】:2018-12-09 20:38:44 【问题描述】:

我正在创建一个发送 API 调用并将结果保存到数据库的应用程序。为了避免一直回到 API 文档,我创建了一个小应用程序来提醒我调用的基本元素。它通过将 xml 文档加载到内存中并使用列表框来选择适当的调用来工作。然后它的元素显示在文本块(和文本框)中。

“apicalls.xml”文件的结构如下:

<Calls>
<Call>
    <Description>blah blah</Description>
    <api>POST /api/something/somethingElse/etc</api>
    <Accept>application/xml</Accept>
    <ContentType>application/xml</ContentType>
    <Parameters>id</Parameters>
    <Method>POST</Method>
    <ReceiveFile>true</ReceiveFile>
    <Category>aCategory</Category>
</Call> </Calls>

有很多“呼叫”元素。所以C#代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Xml;
using System.Windows.Threading;

namespace ShowAPI

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window

    public XmlDocument doc = new XmlDocument();

    public MainWindow()
    
        InitializeComponent();
        doc.Load("apicalls.xml");
    

    private void getAll(string name)
    
        XmlNodeList nodeList = doc.DocumentElement.SelectNodes("Call");
        int i = 0;
        foreach (XmlNode node in nodeList)
        
            XmlNode cat = node.SelectSingleNode("Category");
            if (cat.InnerText == name)
            
                ListBoxItem item = new ListBoxItem();
                item.Content = (++i).ToString() + " " + node.SelectSingleNode("api").InnerText;
                //item.Content = node.SelectSingleNode("api").InnerText;
                item.Name = "N" + i.ToString();
                list.Items.Add(item);
            

        
    

    private void RadioButton_Checked(object sender, RoutedEventArgs e)
    
        string name = (((RadioButton)sender).Content.ToString());
        list.Items.Clear();
        getAll(name);

        dispatch(); // this is to display the items after the listbox has been populated

    

    private void dispatch()
    
        list.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
    


    private static Action EmptyDelegate = delegate ()  ;


    private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
    
        if (list.Items.Count == 0)
            return;

        int index = list.SelectedIndex;
        object sel = e.AddedItems[0];
        string s = sel.ToString();
        XmlNodeList nodes = doc.DocumentElement.SelectNodes("Call");

        IEnumerable<RadioButton> enumerable = panel.Children.OfType<RadioButton>();
        Func<RadioButton, bool> func = (x) => x.IsChecked == true;
        RadioButton res = enumerable.Single<RadioButton>(func);

        string find = res.Content.ToString();
        List<XmlNode> nodeList = new List<XmlNode>();
        foreach (XmlNode xnode in nodes)
        
            XmlNode api_node = xnode.SelectSingleNode(".//api");
            XmlNode cat_node = xnode.SelectSingleNode(".//Category");
            string s_api = api_node.InnerText;
            string s_cat = cat_node.InnerText;

            if (s_cat == find)
            
                nodeList.Add(xnode);
            

        

        XmlNode xxx = nodeList[index];
        description.Text = xxx.SelectSingleNode(".//Description").InnerText;
        api.Text = xxx.SelectSingleNode(".//api").InnerText.TrimStart(new char[]  'G', 'E', ' ', 'T', 'L', 'U', 'P', 'S', 'O', 'D' );
        accept.Text = xxx.SelectSingleNode(".//Accept").InnerText;
        contentType.Text = xxx.SelectSingleNode(".//ContentType").InnerText;
        method.Text = xxx.SelectSingleNode(".//Method").InnerText;
        expectFile.Text = xxx.SelectSingleNode(".//ReceiveFile").InnerText;
        parameters.Text = xxx.SelectSingleNode(".//Parameters").InnerText;


    


这是 xaml 中的 ListBox 实现:

<ListBox Name ="list" HorizontalAlignment="Left" Height="396" Margin="582,52,0,0" VerticalAlignment="Top" Width="561" SelectionChanged="list_SelectionChanged">
        <ListBox.Background>
            <RadialGradientBrush Center="0.1,0.5" GradientOrigin="2,1" RadiusX="1" RadiusY="0.3" SpreadMethod="Reflect">
                <GradientStop Color="#FFC7431C" Offset="1"/>
                <GradientStop Color="#FFD31010" Offset="0.494"/>
            </RadialGradientBrush>
        </ListBox.Background>
    </ListBox>c

所以列表框填充正常,我可以看到所有项目,但是当我将鼠标移到它们上方时,无法选择第 12 个之后的任何项目(它们似乎不是交互式的 - 背景不会改变在项目上移动)。

我尝试将 listboxitems 作为对象而不是文本插入(我在某处读过它),并通过在实际内容之前添加索引号和方法名称来避免插入相同的项目。似乎没有任何工作,我不知道......

附:我还对 GetProperties() 使用了反射,并将第一个 listboxitem 的值与第 14 个 listboxitem 的值进行比较,除了名称和内容之外它们是相同的。 我只是注意到用箭头键选择项目工作正常。 12号之后的任何项目都无法使用鼠标选择。

【问题讨论】:

手动创建 ListBoxItems 有什么特别的原因,而不是仅仅将内容对象添加到 Items 集合中?或者更好的是,将一组项目对象分配或绑定到 ListBox 的 ItemsSource 属性。 @Clemens 我这样做只是因为我在互联网上发现仅添加内容可能是无法选择列表框项目的原因。初始实现作为注释包含在代码中: item.Content = node.SelectSingleNode("api").InnerText; 这仍然需要手动创建 ListBoxItem。为什么不list.Items.Add(node.SelectSingleNode("api").InnerText) @Clemens 对不起!我的错误......这就是我最初使用的,但它没有任何区别...... 您的视图中是否有任何东西覆盖了 ListBox? 【参考方案1】:

似乎有一些元素覆盖了ListBox,例如TextBlock。这就是为什么您不能选择位于覆盖元素“下方”的项目。

删除它,选择应该按预期工作。

【讨论】:

【参考方案2】:

我建议您使用基于 WPF 核心功能(例如 XmlDataProvider 和当前项目同步)略有不同的方法。 所以首先在你的窗口资源中定义一个 XmlDataProvider:

<Window.Resources>
    <XmlDataProvider x:Key="CallsData">
        <x:XData>
            <Calls xmlns=''>
                <Call>
                    <Description>blah blah 3</Description>
                    <api>POST /api/something</api>
                    <Accept>application/xml</Accept>
                    <ContentType>application/xml</ContentType>
                    <Parameters>id</Parameters>
                    <Method>POST</Method>
                    <ReceiveFile>true</ReceiveFile>
                    <Category>Cat1</Category>
                </Call>
                <Call>
                    <Description>blah blah 2</Description>
                    <api>POST /api/something/somethingElse</api>
                    <Accept>application/xml</Accept>
                    <ContentType>application/xml</ContentType>
                    <Parameters>id</Parameters>
                    <Method>POST</Method>
                    <ReceiveFile>true</ReceiveFile>
                    <Category>Cat3</Category>
                </Call>
                <Call>
                    <Description>blah blah 3</Description>
                    <api>POST /api/something/somethingElse/etc</api>
                    <Accept>application/xml</Accept>
                    <ContentType>application/xml</ContentType>
                    <Parameters>id</Parameters>
                    <Method>POST</Method>
                    <ReceiveFile>true</ReceiveFile>
                    <Category>Cat2</Category>
                </Call>
            </Calls>
        </x:XData>
    </XmlDataProvider>
</Window.Resources>

稍后将其绑定到您的列表。像这样:

<DockPanel LastChildFill="True" 
           DataContext="Binding Source=StaticResource CallsData, XPath=/Calls/Call">
    <StackPanel DockPanel.Dock="Bottom">
        <TextBlock Text="Binding XPath=Description, StringFormat='Description = 0'"/>
        <TextBlock Text="Binding XPath=api, StringFormat='api = 0'"/>
        <TextBlock Text="Binding XPath=Accept, StringFormat='Accept = 0'"/>
        <TextBlock Text="Binding XPath=ContentType, StringFormat='ContentType = 0'"/>
        <TextBlock Text="Binding XPath=Parameters, StringFormat='Parameters = 0'"/>
        <TextBlock Text="Binding XPath=Method, StringFormat='Method = 0'"/>
        <TextBlock Text="Binding XPath=ReceiveFile, StringFormat='ReceiveFile = 0'"/>
        <TextBlock Text="Binding XPath=Category, StringFormat='Category = 0'"/>
    </StackPanel>
    <ListBox Name="list" 
            IsSynchronizedWithCurrentItem="True"
            ItemsSource="Binding">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="Binding XPath=Category"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</DockPanel>

【讨论】:

以上是关于无法选择 wpf 列表框项目的主要内容,如果未能解决你的问题,请参考以下文章

使 WPF 中的列表框项目不可选

选择时如何让wpf listboxitem拉伸列表框的整个高度

无法在我的列表框中看到项目的名称,WPF,C#

WPF:停止或反转列表框中的选择更改

WPF:仅当列表框中的一项被选中时才启用按钮

C#WPF如何在由数据模板中的对象列表组成的列表框中设置项目[重复]