无法选择 wpf 列表框项目
wpf listbox items cannot be selected
我正在创建一个发送 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>
有很多 "Call" 个元素。所以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 作为对象而不是文本插入(我在某处读过),并通过在实际内容之前添加索引号和方法名称来避免插入相同的项目。似乎没有任何效果,我也不知道...
P.S。我还使用了对 GetProperties() 的反射,并将第一个列表框项的值与第 14 个列表框项的值进行比较,除了名称和内容之外,它们是相同的。
我只是注意到用箭头键选择项目效果很好。鼠标选择12号之后的任何项目都不起作用
我建议您使用基于 WPF 核心功能(例如 XmlDataProvider
和当前项目同步)的稍微不同的方法。
因此,首先在您的 window 资源中定义一个 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>
似乎有一些元素覆盖了 ListBox
,例如 TextBlock
。这就是为什么您不能 select 位于 "under" 重叠元素的项目。
删除它,selection 应该会按预期工作。
我正在创建一个发送 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>
有很多 "Call" 个元素。所以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 作为对象而不是文本插入(我在某处读过),并通过在实际内容之前添加索引号和方法名称来避免插入相同的项目。似乎没有任何效果,我也不知道...P.S。我还使用了对 GetProperties() 的反射,并将第一个列表框项的值与第 14 个列表框项的值进行比较,除了名称和内容之外,它们是相同的。 我只是注意到用箭头键选择项目效果很好。鼠标选择12号之后的任何项目都不起作用
我建议您使用基于 WPF 核心功能(例如 XmlDataProvider
和当前项目同步)的稍微不同的方法。
因此,首先在您的 window 资源中定义一个 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>
似乎有一些元素覆盖了 ListBox
,例如 TextBlock
。这就是为什么您不能 select 位于 "under" 重叠元素的项目。
删除它,selection 应该会按预期工作。