C# While循环无法按预期从列表中随机选取新字符串

C# While循环无法按预期从列表中随机选取新字符串,c#,wpf,C#,Wpf,作为一个完全的初学者,我认为我在WPF应用程序中犯了一些严重的错误,因为我合并的while循环没有按计划工作 List<string> alreadyUsedReagents = new List<string>(new string[] {}); List<string> alreadyUsedMetals = new List<string>(new string[] { }); List<string> reagents = n

作为一个完全的初学者,我认为我在WPF应用程序中犯了一些严重的错误,因为我合并的while循环没有按计划工作

List<string> alreadyUsedReagents = new List<string>(new string[] {});
List<string> alreadyUsedMetals = new List<string>(new string[] { });

List<string> reagents = new List<string>(new string[]{
        "Hexaaqua ion",
        "Dilute NaOH",
        "Excess NaOH",
        "Dilute NH₃",
        "Excess NH₃",
        "Salt",
        "Na₂CO₃",
        "HCl"});

public void RefreshReagents()
{
    alreadyUsedReagents.Clear();
}

public string CycleThroughReagents()
{
    bool keepinLoop = true;
    string chosenReagent = null;

    while (keepinLoop == true)
    {
        int r = rnd.Next(reagents.Count);
        string pickedReagent = (string)reagents[r];


        if (!alreadyUsedReagents.Contains(pickedReagent))
        {
            alreadyUsedReagents.Add(pickedReagent);
            chosenReagent = pickedReagent;
            keepinLoop = false;
        }

        if (alreadyUsedReagents.Count == 8)
        {
            RefreshReagents();
            keepinLoop = false;
        }
        else
        {
            keepinLoop = true;
        }
    }

    return chosenReagent;
}
此方法中实现了开关功能,如果按钮与试剂组匹配,则将特定按钮的标签设置为“正确”

public partial class MainWindow : Window
{
    GameControl _GameControl = new GameControl();
    public string chosenMetal;
    int amtLeft = 8;


    public MainWindow()
    {
        InitializeComponent();
        chosenMetal = _GameControl.CycleThroughMetals();
        _GameControl.SetButtonContent(chosenMetal,ReagentAdded, transMetal, Opt1, Opt2, Opt3, Opt4, Opt5, Opt6, Opt7, Opt8);

        Opt1.Click += HandleButtonClicks;
        Opt2.Click += HandleButtonClicks;
        Opt3.Click += HandleButtonClicks;
        Opt4.Click += HandleButtonClicks;
        Opt5.Click += HandleButtonClicks;
        Opt6.Click += HandleButtonClicks;
        Opt7.Click += HandleButtonClicks;
        Opt8.Click += HandleButtonClicks;  
    }

    public void SwitchMetals()
    {
        chosenMetal = _GameControl.CycleThroughMetals();
        _GameControl.RefreshReagents(); //method which clears the 'alreadyUsedReagents' list
        _GameControl.SetButtonContent(chosenMetal, ReagentAdded, transMetal, Opt1, Opt2, Opt3, Opt4, Opt5, Opt6, Opt7, Opt8);
    }

    private void HandleButtonClicks(object sender, RoutedEventArgs e)
    {
        Button button = sender as Button;
        CheckForCorrect(button);

    }

    public void CheckForCorrect(Button button)
    {
        if ((string)button.Tag == "correct" && amtLeft != 0)
        {
            amtLeft -= 1;
            MessageBox.Show("You guessed correct!");
            _GameControl.SetButtonContent(chosenMetal, ReagentAdded, transMetal, Opt1, Opt2, Opt3, Opt4, Opt5, Opt6, Opt7, Opt8);
            button.IsEnabled = false;
        }

        if ((string)button.Tag != "correct")
        {
            MessageBox.Show("Oops!");
        }

        else if (amtLeft == 0)
          SwitchMetals();


    }
}

然后在
主窗口中使用上述方法最初设置按钮和试剂文本,然后使用单击方法查看单击的按钮是否正确,如果正确,则设置新试剂。我遇到的问题是,我处理试剂循环和设置的方式似乎完全弄乱了我的代码,就像每次单击后屏幕上显示试剂一样,有时
TextBlock
显示为空白,并使用以前使用过的试剂。任何帮助都将不胜感激,我很抱歉提前包含了这么多代码示例,但我真的很难从这里开始做什么。

看看while循环,这篇文章似乎:

if (!alreadyUsedReagents.Contains(pickedReagent))
{
    alreadyUsedReagents.Add(pickedReagent);
    chosenReagent = pickedReagent;
    keepinLoop = false;
}
应该执行
中断
。它当前的工作方式不会阻止循环的进一步迭代,因为您在
keepinloop
中设置的值可以被下面的if/else覆盖。所以试着换一条线

keepinLoop = false;

这应该可以修复你的循环

更新。实际上,与其使用某些虚构的标志来控制循环,不如使用一些真实的条件,如使用的试剂数量,例如:

while (alreadyUsedReagents.Count != 8)
{
    int r = rnd.Next(reagents.Count);
    string pickedReagent = (string)reagents[r];

    if (!alreadyUsedReagents.Contains(pickedReagent))
    {
        alreadyUsedReagents.Add(pickedReagent);
        chosenReagent = pickedReagent;
        break;
    }
}
RefreshReagents();

if (chosenReagent == null)
{
    // make sure to come up with some default
    // or your method will return null in some cases
}

如果您没有跟踪
alreadyusedAgentures
而是保留了
unusedAgentures
的列表,那么您完全可以不进行任何循环

refreshAgents()
然后用整个列表填充
unusedAgents

cyclethrawagents()
随机选取一个,将其从
unusedagents
中移除并返回


每当
unusedagreents
为空时调用
refreshAgreents()

如果您正在这样做,则只需将while设置为loop on true
while(true)
因为您不再使用
keepinLoop
。OP需要处理的下一件事是当您返回到
cyclethrawagents()
alreadyusedagents.Count==8
时,它将返回一个空字符串。谢谢!,这修复了TextBlock显示为空白并使用以前使用的文本块的问题reagents@evanb,那么也许最好的方法是执行类似于
的操作,而(count!=8)
。事实上,让我用这个更新答案。同时提到你对null的观察我无法停止阅读KeepLoopin,因为KeepLoopin‘我没有读过你的代码,但是你的描述表明你做的都是错的。既然你可以记住那些没有被选中的项目,为什么还要记住那些已经被选中的项目呢?首先将所有项目放入第二个列表,使用
Random
实例随机选择一个项目,然后从列表中删除该项目。继续这样做,直到列表为空,然后在需要时重新填充。@CallumHoughton继续学习,不要害怕新手犯错误。我们都去过那里。@jmcilhinney这基本上就是我发布的答案。@CoderDennis,我写评论时没有评论或答案,但我遇到了连接问题,所以在它实际发布时已经发生了很多活动。这听起来比我目前的解决方案干净多了,我会在早上尝试。谢谢你的回答
break;
while (alreadyUsedReagents.Count != 8)
{
    int r = rnd.Next(reagents.Count);
    string pickedReagent = (string)reagents[r];

    if (!alreadyUsedReagents.Contains(pickedReagent))
    {
        alreadyUsedReagents.Add(pickedReagent);
        chosenReagent = pickedReagent;
        break;
    }
}
RefreshReagents();

if (chosenReagent == null)
{
    // make sure to come up with some default
    // or your method will return null in some cases
}