选择组中的下一个单选按钮

Posted

技术标签:

【中文标题】选择组中的下一个单选按钮【英文标题】:Selecting the next radio button in a group 【发布时间】:2013-01-15 22:08:01 【问题描述】:

是否有一种标准方法可以以编程方式选择/检查一组单选按钮中的下一个单选按钮?我正在寻找的行为类似于分组在容器中的单选按钮的默认箭头键按下事件:当我按下箭头键时,会自动选择并检查下一个(或上一个)单选按钮。

【问题讨论】:

我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。 【参考方案1】:

我是这样制作的:

    var rads = panel1.Controls.OfType<RadioButton>(); // Get all radioButtons of desired panel

    rads.OrderBy(r => r.Top); // sort them. Please specify what you mean "next" here. I assume that you need next one at the bottom

    // find first checked and set checked for next one
    for (int i = 0; i < rads.Count()-1; i++) 
    
        if (rads.ElementAt(i).Checked)
        
            rads.ElementAt(i + 1).Checked = true; 
            return;
        
    

【讨论】:

当多个单选按钮具有相同的 TabIndex 时,Windows 似乎在循环单选按钮时使用的排序方法首先按 TabIndex 排序,然后按 z 顺序排序。此外,这里提出的方法不允许选择循环回第一个单选按钮。不过,我确实从您的回答中获得了灵感。所以谢谢!【参考方案2】:

每个容器只能检查一个RadioButton。这就是单选按钮的意义所在。如果您想改用CheckBox,可以使用以下代码:

foreach (CheckBox control in Controls.OfType<CheckBox>())

    control.Checked = true;

如果你想按顺序检查控件,你可以这样做

new Thread(() =>

    foreach (CheckBox control in Controls.OfType<CheckBox>())
    
        control.BeginInvoke((MethodInvoker) (() => control.Checked = true));
        Thread.Sleep(500);
    
).Start();

再次阅读您的原始帖子时,我很难理解您的意思。您能否详细说明一下,以便我更新我的回复?

【讨论】:

澄清:假设我在一个面板中有 5 个单选按钮。假设当前选择了第三个(选中)。我想在不使用鼠标或键盘的情况下以编程方式选择(检查)面板中的下一个单选按钮。【参考方案3】:

最快的解决方案:(如果您的应用程序有焦点...)

//assuming you are at the first radio button
SendKeys(DOWN);

更难的解决方案: http://msdn.microsoft.com/en-us/library/system.windows.automation.automationelement.findall.aspx

//Write method to get window element for the window you wish to manipulate
//Open an instance of notepad and the WindowTitle is: "Untitled - Notepad"
//you could use other means of getting to the Window element ...
AutomationElement windowElement = getWindowElement("Untitled - Notepad");

//Use System.Windows.Automation to find all radio buttons in the WindowElement
//pass the window element into this method
//This method will return all of the radio buttons in the element that is passed in
//however, if you have a Pane inside of the WIndow and then, the buttons are contained
//in the pane, you will have to get to the pane and then pass the pane into the findradiobuttons method
AutomationElementCollection radioButtons = FindRadioButtons(windowElement);

//could iterate through the radioButtons to determine which is selected...
//then select the next index etc.    

//then programmatically select the radio button
//pass the selected radioButton AutomationElement into a method that Invokes the Click etc.
clickButtonUsingUIAutomation(radioButtons[0]);

/// <summary> 
/// Finds all enabled buttons in the specified window element. 
/// </summary> 
/// <param name="elementWindowElement">An application or dialog window.</param>
/// <returns>A collection of elements that meet the conditions.</returns>
AutomationElementCollection FindRadioButtons(AutomationElement elementWindowElement)

    if (elementWindowElement == null)
    
        throw new ArgumentException();
    
    Condition conditions = new AndCondition(
      new PropertyCondition(AutomationElement.IsEnabledProperty, true),
      new PropertyCondition(AutomationElement.ControlTypeProperty, 
          ControlType.RadioButton)
      );

    // Find all children that match the specified conditions.
    AutomationElementCollection elementCollection = 
    elementWindowElement.FindAll(TreeScope.Children, conditions);
    return elementCollection;


    private AutomationElement getWindowElement(string windowTitle)
    
        AutomationElement root = AutomationElement.RootElement;
        AutomationElement result = null;
        foreach (AutomationElement window in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window)))
        
            try
            
                if (window.Current.Name.Contains(windowTitle) && window.Current.IsKeyboardFocusable)
                
                    result = window;
                    break;
                
            
            catch (Exception e)
            
                throw;
            
        

        return result;
    

    private void ClickButtonUsingUIAutomation(AutomationElement control)
    
        // Test for the control patterns of interest for this sample. 
        object objPattern;
        ExpandCollapsePattern expcolPattern;

        if (true == control.TryGetCurrentPattern(ExpandCollapsePattern.Pattern, out objPattern))
        
            expcolPattern = objPattern as ExpandCollapsePattern;
            if (expcolPattern.Current.ExpandCollapseState != ExpandCollapseState.LeafNode)
            
                Button expcolButton = new Button();
                //expcolButton.Margin = new Thickness(0, 0, 0, 5);
                expcolButton.Height = 20;
                expcolButton.Width = 100;
                //expcolButton.Content = "ExpandCollapse";
                expcolButton.Tag = expcolPattern;
                expcolPattern.Expand();
                //SelectListItem(control, "ProcessMethods");
                //expcolButton.Click += new RoutedEventHandler(ExpandCollapse_Click);
                //clientTreeViews[treeviewIndex].Children.Add(expcolButton);
            
        
        TogglePattern togPattern;
        if (true == control.TryGetCurrentPattern(TogglePattern.Pattern, out objPattern))
        
            togPattern = objPattern as TogglePattern;
            Button togButton = new Button();
            //togButton.Margin = new Thickness(0, 0, 0, 5);
            togButton.Height = 20;
            togButton.Width = 100;
            //togButton.Content = "Toggle";
            togButton.Tag = togPattern;
            togPattern.Toggle();
            //togButton.Click += new RoutedEventHandler(Toggle_Click);
            //clientTreeViews[treeviewIndex].Children.Add(togButton);
        
        InvokePattern invPattern;
        if (true == control.TryGetCurrentPattern(InvokePattern.Pattern, out objPattern))
        
            invPattern = objPattern as InvokePattern;
            Button invButton = new Button();
            //invButton.Margin = new Thickness(0);
            invButton.Height = 20;
            invButton.Width = 100;
            //invButton.Content = "Invoke";
            invButton.Tag = invPattern;
            //invButton.Click += new EventHandler(Invoke_Click);
            invPattern.Invoke();

            //clientTreeViews[treeviewIndex].Children.Add(invButton);
        

    

【讨论】:

【参考方案4】:

所以,似乎没有标准的方法来处理这个问题。我最终从 Andrey 的解决方案中获得灵感,并编写了一个扩展方法,该方法可以从一组 RadioButton 中的任何特定 RadioButton 调用。

public static void CheckNextInGroup(this RadioButton radioButton, bool forward) 
    var parent = radioButton.Parent;
    var radioButtons = parent.Controls.OfType<RadioButton>();  //get all RadioButtons in the relevant container
    var ordered = radioButtons.OrderBy(i => i.TabIndex).ThenBy(i => parent.Controls.GetChildIndex(i)).ToList();  //Sort them like Windows does
    var indexChecked = ordered.IndexOf(radioButtons.Single(i => i.Checked)); //Find the index of the one currently checked
    var indexDesired = (indexChecked + (forward ? 1 : -1)) % ordered.Count;  //This allows you to step forward and loop back to the first RadioButton
    if (indexDesired < 0) indexDesired += ordered.Count;  //Allows you to step backwards to loop to the last RadioButton
    ordered[indexDesired].Checked = true;

然后,从可以访问您的特定 RadioButton 的任何地方,您可以检查其集合中的下一个或上一个 RadioButton。像这样:

radioButton1.CheckNextInGroup(true); //Checks the next one in the collection
radioButton1.CheckNextInGroup(false); //Checks the previous one in the collection

【讨论】:

以上是关于选择组中的下一个单选按钮的主要内容,如果未能解决你的问题,请参考以下文章

在从单选组中选择单选按钮时设置变量值

更改单选按钮选中状态时如何从单选按钮组中的单选按钮获取文本

当用户从颤动的单选按钮组中选择单选按钮时如何保存数据?

是否可以更改android单选按钮组中的单选按钮图标

设置变量值,从无线电组中选择一个单选按钮

我想在页面加载时检查某些单选按钮组中的某些特定单选按钮?