C# 如何在Unity中筛选/搜索列表
我正试图想出一种方法来过滤我动态创建的按钮列表,该列表基于SQlite DB中循环的值。每个按钮都标有学生姓名,可能有大量按钮,因此需要过滤按钮 我创建的按钮如下所示:C# 如何在Unity中筛选/搜索列表,c#,unity3d,filtering,C#,Unity3d,Filtering,我正试图想出一种方法来过滤我动态创建的按钮列表,该列表基于SQlite DB中循环的值。每个按钮都标有学生姓名,可能有大量按钮,因此需要过滤按钮 我创建的按钮如下所示: public RectTransform GridWithNameElements; public GameObject StudentNamePrefabButton; while (reader.Read()) { //create a new button obje
public RectTransform GridWithNameElements;
public GameObject StudentNamePrefabButton;
while (reader.Read())
{
//create a new button object and use the prefab button to make sure spacing etc is correct
goButton = (GameObject)Instantiate(StudentNamePrefabButton);
//set the parent of the button
goButton.transform.SetParent(GridWithNameElements, false);
goButton.transform.localScale = new Vector3(1, 1, 1);
//set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
goButton.GetComponentsInChildren<Text>()[0].text = reader["fullName"].ToString()+" | "+ reader["studentNumber"].ToString();
goButton.name = reader["studentID"].ToString();
Button tempButton = goButton.GetComponent<Button>();
int tempInt = i;
tempButton.onClick.AddListener(() => ButtonClicked(tempInt));
i++;
Debug.Log(goButton.name);
}
我希望简单地遍历所有列表项,并隐藏那些与搜索查询不匹配的项。然而,目前,我的循环是错误的,因为我得到了一个越界异常(我认为这与在进行搜索时动态添加一个新的子元素有关)。我在控制台日志中看到了这一点,但是,程序按预期执行(因此这是一个问题,但目前不是最大的问题)
我隐藏原始列表,并根据匹配条件显示新列表
然而,我只返回一个可能的名字,而不是一堆可能的选择。例如,根据我目前的代码,如果我有本·琼斯和鲍勃·迪伦的名字,我只能返回本·琼斯,而不能返回鲍勃·迪伦
我觉得我在做这件事时走错了方向,因为我想要类似的东西,但无法重现。然而,我正试图弄清楚我是否朝着正确的方向前进
更新
我想我已经找到了索引自动失效异常的原因:数组索引超出范围。
这是因为每当我键入字母时,它都在调用SearchExistingStudentName()
方法。这意味着,只要在其中一个名称中找到键入的字母,它就会被添加到列表中—仅添加字母。这就是为什么我只能返回一个名字,而不是可能的名字列表。因此,我认为国际单项体育联合会的声明需要修改,我现在正在努力研究这一点
我已设法将代码中的数组异常缩小到本节:
//Loop through and hide all children and hide them
if (count == 0)
{
foreach (Transform child in GridWithNameElements)
{
child.gameObject.SetActive(false);
}
}
count++;
//Then create a button that represents a name added to the names List
newButton = (GameObject)Instantiate(StudentNamePrefabButton);
//set the parent of the button
newButton.transform.SetParent(GridWithNameElements, false);
newButton.transform.localScale = new Vector3(1, 1, 1);
//set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
newButton.GetComponentsInChildren<Text>()[filteredNameCount].text = names[filteredNameCount].ToString();
newButton.name = names[filteredIDCount].ToString().Trim();
newButton.tag = "filterButton";
filteredNameCount++;
filteredIDCount++;
//循环并隐藏所有子项并隐藏它们
如果(计数=0)
{
foreach(在GridWithNameElements中转换子级)
{
child.gameObject.SetActive(false);
}
}
计数++;
//然后创建一个按钮,该按钮表示添加到名称列表中的名称
newButton=(游戏对象)实例化(StudentNameButton);
//设置按钮的父级
SetParent(GridWithNameElements,false);
newButton.transform.localScale=新向量3(1,1,1);
//设置按钮的文本。数组值为0,因为学生名称在每次迭代中始终位于位置0
newButton.GetComponentsInChildren()[filteredNameCount].text=名称[filteredNameCount].ToString();
newButton.name=名称[FilterEdicount].ToString().Trim();
newButton.tag=“filterButton”;
filteredNameCount++;
filterediccount++;
既然您已经用Unity3D标记了此代码,我假设您希望在游戏中使用此代码。如果是这种情况,我不建议使用LINQ,如果可以用更传统的方式轻松获得相同的结果。话虽如此,我将展示这两种方法
List<string> names = GridWithNameElements.Where(nameInList => nameInList.Contains(input))
我对变量的类型不完全有信心,但我认为结构应该足够清晰。如果不是的话,请随意询问更多问题。最终我自己设法解决了这个问题,尽管这远不是一个优雅的解决方案,但它还是有效的。我现在将致力于改进代码本身,但对于那些可能需要一个起点的人,我想我会分享我所做的 正如在我的问题中提到的,我在我的主、未过滤的可滚动列表上循环了一系列按钮
while (reader.Read())
{
//create a new button object and use the prefab button to make sure spacing etc is correct
GameObject goButton = (GameObject)Instantiate(StudentNamePrefabButton);
//set the parent of the button
goButton.transform.SetParent(GridWithNameElements, false);
goButton.transform.localScale = new Vector3(1, 1, 1);
//set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
goButton.GetComponentsInChildren<Text>()[0].text = reader["fullName"].ToString() + " | " + reader["studentNumber"].ToString();
goButton.name = reader["studentID"].ToString();
Button tempButton = goButton.GetComponent<Button>();
int tempInt = i;
tempButton.onClick.AddListener(() => ButtonClicked(tempInt));
i++;
Debug.Log(goButton.name);
}
为什么不在循环中使用
nameInList
变量?关于使用切换呢?也许会让你的生活更轻松!谢谢你的回答。自从你发布这篇文章以来,我已经为我的问题添加了更多的细节,因为我觉得解决方案比最初解释的要复杂一些。我无法使用您的字符串名称列表的语法
,因为我遇到了一个错误,即无法从源类型转换为目标类型
。我现在使用的是一个简单的for循环,如更新中所示。我比以前更进一步了,但正如更新的问题所表明的,仍然存在一些bug。
List<string> names = new List<string>();
foreach (string nameInList in GridWithNameElements)
{
if (nameInList.Contains(input)
{
names.Add(nameInList)
}
}
while (reader.Read())
{
//create a new button object and use the prefab button to make sure spacing etc is correct
GameObject goButton = (GameObject)Instantiate(StudentNamePrefabButton);
//set the parent of the button
goButton.transform.SetParent(GridWithNameElements, false);
goButton.transform.localScale = new Vector3(1, 1, 1);
//set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
goButton.GetComponentsInChildren<Text>()[0].text = reader["fullName"].ToString() + " | " + reader["studentNumber"].ToString();
goButton.name = reader["studentID"].ToString();
Button tempButton = goButton.GetComponent<Button>();
int tempInt = i;
tempButton.onClick.AddListener(() => ButtonClicked(tempInt));
i++;
Debug.Log(goButton.name);
}
//This method is called when the student attempts to search for their own name when taking the individual quiz
public void SearchExistingStudentName()
{
//Get the name entered from the text field
string student_name = searchExistingStudentNameInput.text;
//Create a list to store all the user names
List<string> filteredNamesList = new List<string>();
//Add another list to store the user unique ids
List<string> filteredNameIDList = new List<string>();
//Clear both lists before using them
filteredNamesList.Clear();
filteredNameIDList.Clear();
//sets an id to the onclick listener of newly created buttons
int x = 0;
//if a new button object exists and the name was entered and then removed, clear it from the list and remove the created button
if (student_name == "")
{
//Clear the filtered filteredNamesList List
filteredNamesList.Clear();
filteredNameIDList.Clear();
x = 0;
//Destroy the create filter buttons if the user clears the text area
GameObject[] objects = GameObject.FindGameObjectsWithTag("filterButton");
//loop through the buttons that share the tag "filterButton"
for (int count = 0; count < objects.Length; count++)
{
Destroy(objects[count]);
Debug.Log("Number of objects to be deleted " + objects.Length);
}
//Loop through and show all children
foreach (Transform child in GridWithNameElements)
{
child.gameObject.SetActive(true);
}
GridWithNameElements.gameObject.SetActive(true);
GridWithNameElements2.gameObject.SetActive(false);
}
else if (student_name != "")
{
//loop through the list of buttons in the main/unfiltered list with student filteredNamesList
for (int i = 0; i < GridWithNameElements.childCount; i++)
{
//Check if the user has typed their name with capitals or lowercase etc, and check the inputted value against filteredNamesList already in the list
//If true, proceed
//Get the name value that contains entered character
if (GridWithNameElements
.GetComponentsInChildren<Text>()[i].text.Contains(student_name) || GridWithNameElements
.GetComponentsInChildren<Text>()[i].text.ToLower().Contains(student_name) || GridWithNameElements
.GetComponentsInChildren<Text>()[i].text.ToUpper().Contains(student_name))
{
//Do not allow duplicates to the list
if (filteredNamesList.Distinct().Count() == filteredNamesList.Count())
{
//If the name entered contains letters found in the parent GridWithNameElements, then add them to the list array and their name value (unique id)
filteredNamesList.Add(GridWithNameElements.GetComponentsInChildren<Text>()[i].text.Replace(@"[", string.Empty).Replace(@"]", string.Empty));
filteredNameIDList.Add(GridWithNameElements.GetChild(i).name); //this is the unique id of the student
}
//end of if statement
}
//end of main loop
}
//hide original list
GridWithNameElements.gameObject.SetActive(false);
//show filtered list
GridWithNameElements2.gameObject.SetActive(true);
//Destroy the created filter buttons if the user presses another button, as previously
//added filteredNamesList might need to be ruled out.
GameObject[] objects = GameObject.FindGameObjectsWithTag("filterButton");
//loop through the buttons that share the tag "filterButton"
for (int count = 0; count < objects.Length; count++)
{
Destroy(objects[count]);
Debug.Log("Number of objects to be deleted " + objects.Length);
}
int filteredNameIDCount = 0;
foreach (string nameInList in filteredNamesList)
{
//Then create a button that represents a name added to the filteredNamesList List
newButton = Instantiate(StudentNamePrefabButton);
//set the parent of the button
newButton.transform.SetParent(GridWithNameElements2, false);
newButton.transform.localScale = new Vector3(1, 1, 1);
//set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
newButton.GetComponentsInChildren<Text>()[0].text = nameInList.ToString();
newButton.name = filteredNameIDList[filteredNameIDCount].ToString().Trim();
newButton.tag = "filterButton";
Debug.Log("Filtered Name " + nameInList.ToString() + " Their ID " + filteredNameIDList[filteredNameIDCount].ToString().Trim());
filteredNameIDCount++;
}
//end of loop
//Then add a click listener to the button
Button tempButton = newButton.GetComponent<Button>();
int tempInt = x;
tempButton.onClick.AddListener(() => ButtonClicked(tempInt));
x++;
// Debug.Log("Student Unique ID " + newButton.name);
}
}