我正在尝试根据从SQlite DB循环的值来过滤我动态创建的按钮列表的方法。每个按钮都标有学生姓名,可能有大量按钮,因此需要过滤按钮。
我按钮创建我的按钮:
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);
}
然后我创建了一个输入字段并将一个脚本附加到输入字段中的onValueChanged
并尝试编写脚本。
//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;
//Add names that exist to the new list
List<string> names = new List<string>();
names.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 names List
names.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);
}
}
else if (student_name != "")
{
int count = 0;
int filteredNameCount = 0;
int filteredIDCount = 1;
//loop through the list of buttons with student names
for (int i = 0; i < GridWithNameElements.childCount; i++)
{
Debug.Log("Children of grid "+GridWithNameElements.childCount);
//Check if the user has typed their name with capitals or lowercase etc, and check the inputted value against names already in the list
//If true, proceed
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))
{
//If the name entered contains letters found in the parent GridWithNameElements, then add them to the list array and their name value (unique id)
names.Add(GridWithNameElements.GetComponentsInChildren<Text>()[i].text.Replace(@"[", string.Empty).Replace(@"]", string.Empty));
names.Add(GridWithNameElements.GetChild(i).name); //this is the unique id of the student
Debug.Log("Number of items in filtered names list " + names.Count);
//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++;
//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);
}
}
count = 0;
}
}
我希望简单地遍历所有列表项,并隐藏那些与搜索查询不匹配的项。但是,目前,我的循环是错误的,因为我得到一个越界异常(我认为这与在搜索时动态添加新的子元素有关)。我在控制台日志中看到了这一点,然而,程序按预期执行(所以这是一个问题,但目前不是最大的问题)。
我隐藏原始列表并根据匹配条件显示新列表。
然而,我只返回一个可能的名字,而不是一堆可能的选择。例如,如果我的名字是Ben Jones和Bob Dylan,根据我的代码,我只能返回Ben Jones而不是Bob Dylan。
我觉得我这样做是错误的,因为我想要类似于this的东西,并且无法重新创建它。但是,如果我朝着正确的方向前进,我想弄明白。
更新
我想我找到了IndexOutOfRangeException: Array index is out of range.
的原因这是因为每当我输入一个字母时,它都会调用SearchExistingStudentName()
方法。这意味着只要在其中一个名称中找到键入的字母,它就会被添加到列表中 - 只有字母。这就是为什么我只能返回一个名称,而不是一个可能的名称列表。因此,我认为if语句需要修改,我现在正在努力研究。
我已经设法缩小了本节代码中的数组异常:
//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 :(得分:1)
由于您已使用Unity3D对此进行了标记,我假设您希望在游戏中使用此代码。如果是这种情况我不建议使用LINQ,如果可以以更传统的方式轻松获得相同的结果。话虽如此,我将展示这两种方法。
List<string> names = GridWithNameElements.Where(nameInList => nameInList.Contains(input))
以上查找nameInList.Contains(input)
评估true
的所有名称。
在循环中,您可以执行以下操作。
List<string> names = new List<string>();
foreach (string nameInList in GridWithNameElements)
{
if (nameInList.Contains(input)
{
names.Add(nameInList)
}
}
我对变量的类型并不完全有信心,但我认为结构应该足够清晰。如果不是,请随意再询问一下。
答案 1 :(得分:0)
最终管理自己解决这个问题,虽然它远非一个优雅的解决方案,但它确实有效。我现在正致力于改进代码本身,但对于那些可能需要起点的人,我想我会分享我所做的。
正如我在问题中所提到的,我将一堆按钮循环到我的主要未经过滤的可滚动列表上。
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);
}
然后我在用户界面中创建了一个用户inputfield
,以便用户可以搜索他们的名字。然后附上一个听众。要执行此操作,请转到Unity编辑器并将脚本附加到On Value Changed
方法。
每次用户输入您的inputfield
时,都会调用附加的脚本。
然后我最终做了以下事情 - 再次,我强调,我刚刚开始工作这不是一个完美的例子,但至少是一个起点,可能还有更多的错误需要解决。我希望它有所帮助,因为我在寻找时没有找到任何完整的例子。
//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);
}
}