原文地址:http://blog.csdn.net/xinyaping/article/details/7887663adio button 通常的行为是:某一组 Radio button 只能有一个被选中( Checked ),当一个被选中是其余的 Radio button 自动 Uncheck。但是,有没有什么办法让这一组 Radio button 在被点击之后,再回复到任何一个 Radio button 都没有被选中的状态呢?比如说,两个 Radio button:Radio 1 和 Radio 2,初始状态下任何一个 radio button 都没有被选中,现在我们点击 Radio 1,则 Radio 1 被选中;再次点击 Radio 1,则 Radio 1 回复到没有被选中的状态,Radio 2 的状态也不受影响。能否实现这样的功能呢?网上搜不到现成的答案,但实际上是可以实现的。实现的关键是利用 RadioButton 的 PreviewMouseLeftButtonDown 事件,该事件能够获得 RadioButton 被点击时,它之前的状态。有了这个状态我们就可以判断出这个 RadioButton 应该从未选中的状态置为选中的状态,还是从被选中的状态置为未选中的状态。
我写了个小例子,可从此处下载源代码和编译好之后的可执行文件(基于.Net 3.5)
http://download.csdn.net/detail/xinyaping/4513569源代码如下:MainWindow.xaml
    <Window x:Class="RadioButttonUnCheckDemo.MainWindow"  
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
            Width="300" Height="95" WindowStyle="ToolWindow"   
            Title="Demo: Uncheckable radio buttons">  
          
        <Grid Height="24" Margin="0,0,0,0">  
            <Grid.ColumnDefinitions>  
                <ColumnDefinition Width="80" />  
                <ColumnDefinition />  
                <ColumnDefinition Width="120" />  
            </Grid.ColumnDefinitions>  
              
            <Label Grid.Column="0" VerticalAlignment="Center">Please select: </Label>  
              
            <WrapPanel Grid.Column="1">  
                <RadioButton Name="radio1" Content="1" Margin="5,0,5,0" GroupName="GroupName1"   
                             PreviewMouseLeftButtonDown="RadioButton_PreviewMouseLeftButtonDown"   
                             Checked="RadioButton_StateChanged"   
                             Unchecked="RadioButton_StateChanged" />  
                <RadioButton Name="radio2" Content="2" Margin="5,0,5,0" GroupName="GroupName1"   
                             PreviewMouseLeftButtonDown="RadioButton_PreviewMouseLeftButtonDown"  
                             Checked="RadioButton_StateChanged"   
                             Unchecked="RadioButton_StateChanged" />  
            </WrapPanel>  
      
            <Label Grid.Column="2" VerticalAlignment="Center" Name="labelResult" />  
        </Grid>   
    </Window>  
MainWindow.xaml.cs 
    namespace RadioButttonUnCheckDemo  
    {  
        using System.Windows;  
        using System.Windows.Controls;  
        using System.Windows.Input;  
      
        /// <summary>  
        /// Interaction logic for MainWindow.xaml  
        /// </summary>  
        public partial class MainWindow : Window  
        {  
            /// <summary>  
            /// Initializes a new instance of the <see cref="MainWindow"/> class.  
            /// </summary>  
            public MainWindow()  
            {  
                this.InitializeComponent();  
            }  
      
            /// <summary>  
            /// Gets a value indicating whether RadioButton radio1 is checked.  
            /// </summary>  
            /// <value>  
            ///     <c>true</c> if RadioButton radio1 is radio1 checked; otherwise, <c>false</c>.  
            /// </value>  
            private bool IsRadio1Checked  
            {  
                get { return this.radio1.IsChecked == null ? false : (bool)this.radio1.IsChecked; }  
            }  
      
            /// <summary>  
            /// Gets a value indicating whether RadioButton radio2 is checked.  
            /// </summary>  
            /// <value>  
            ///     <c>true</c> if RadioButton radio2 is radio1 checked; otherwise, <c>false</c>.  
            /// </value>  
            private bool IsRadio2Checked  
            {  
                get { return this.radio2.IsChecked == null ? false : (bool)this.radio2.IsChecked; }  
            }  
      
            /// <summary>  
            /// Handles the PreviewMouseLeftButtonDown event of the RadioButton control.  
            /// </summary>  
            /// <param name="sender">The source of the event.</param>  
            /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>  
            private void RadioButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)  
            {  
                if (sender != null && sender is RadioButton)  
                {  
                    RadioButton radioButton = sender as RadioButton;  
                    bool isChecked =  
                        radioButton.IsChecked == null ?  
                        false :  
                        (bool)radioButton.IsChecked;  
      
                    if (isChecked)  
                    {  
                        radioButton.IsChecked = false;  
                        e.Handled = true;  
                    }  
                }  
            }  
      
            /// <summary>  
            /// Handles the StateChanged event of the RadioButton control.  
            /// </summary>  
            /// <param name="sender">The source of the event.</param>  
            /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>  
            private void RadioButton_StateChanged(object sender, RoutedEventArgs e)  
            {  
                this.SetResult();  
            }  
      
            /// <summary>  
            /// Sets the result.  
            /// </summary>  
            private void SetResult()  
            {  
                if (!this.IsRadio1Checked && !this.IsRadio2Checked)  
                {  
                    this.labelResult.Content = "Selected: N/A";  
                }  
                else if (this.IsRadio1Checked)  
                {  
                    this.labelResult.Content = "Selected: Radio 1";  
                }  
                else if (this.IsRadio2Checked)  
                {  
                    this.labelResult.Content = "Selected: Radio 2";  
                }  
            }  
        }  
    }  
可从此处下载源代码和编译好之后的可执行文件(基于.Net 3.5)
http://download.csdn.net/detail/xinyaping/4513569

解决方案 »

  1.   


    我勒个去,都玩上了这样的应当dev也有吧,貌似是的。没记错的话。
      

  2.   

    看得出来楼主学习WPF的时间不是很长
      

  3.   

    在WPF下,推荐使用类似以下的解决方案(当然这个方案,包括楼主的方案都是不够严谨的,只能适应鼠标操作的场合):namespace test
    {
        public static class RadioButtonBehavior
        {
            public static bool GetUncheckable(DependencyObject obj)
            {
                return (bool)obj.GetValue(UncheckableProperty);
            }        public static void SetUncheckable(DependencyObject obj, bool value)
            {
                obj.SetValue(UncheckableProperty, value);
            }        public static readonly DependencyProperty UncheckableProperty =
                DependencyProperty.RegisterAttached("Uncheckable", typeof(bool), typeof(RadioButton), new UIPropertyMetadata(false, OnUncheckedableChanged));        private static void OnUncheckedableChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                RadioButton radio = obj as RadioButton;
                if (radio != null)
                {
                    if (Object.Equals(e.NewValue, true))
                    {
                        radio.PreviewMouseLeftButtonDown -= OnRadioPreviewMouseLeftButtonDown;
                        radio.PreviewMouseLeftButtonDown += OnRadioPreviewMouseLeftButtonDown;
                    }
                    else
                    {
                        radio.PreviewMouseLeftButtonDown -= OnRadioPreviewMouseLeftButtonDown;
                    }
                }
            }        private static void OnRadioPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
            {
                RadioButton radio = sender as RadioButton;
                if (radio != null)
                {
                    if (radio.IsChecked == true)
                    {
                        radio.IsChecked = false;
                        e.Handled = true;
                    }
                }
            }
        }
    }
        <StackPanel xmlns:t="clr-namespace:test">
            <RadioButton Content="AAA" t:RadioButtonBehavior.Uncheckable="True" />
            <RadioButton Content="BBB" t:RadioButtonBehavior.Uncheckable="True" />
        </StackPanel>
      

  4.   

    原文地址:http://blog.csdn.net/xinyaping/article/details/7887663
      

  5.   

    如果用mvvm,直接通过属性也可以控制:
    public int? Status
    {
        get { return _status; }
        set {
            if (value != null)
            {
                _status = value == _status ? null : value;
                RaisePropertyChanged("Status");
            }
        }
    }其中 _status 在赋值时判断value是否重复设定,如果是则清空(null)<RadioButton Content="待办"   GroupName="status"  Margin="10"  Height="16"  VerticalAlignment="Center" IsChecked="{Binding SomeObj.Status, Converter={StaticResource intToBoolConverter},ConverterParameter=1, Mode=TwoWay}"/>
                <RadioButton Content="处理中" GroupName="status"  Margin="10"  Height="16"  VerticalAlignment="Center" IsChecked="{Binding SomeObj.Status, Converter={StaticResource intToBoolConverter},ConverterParameter=2, Mode=TwoWay}"/>
                <RadioButton Content="已完成" GroupName="status"  Margin="10"  Height="16"  VerticalAlignment="Center" IsChecked="{Binding SomeObj.Status, Converter={StaticResource intToBoolConverter},ConverterParameter=3, Mode=TwoWay}"/>
      

  6.   

    但是11楼,真的没感觉到您这么写有什么好处~~而且你程序里还有不小的bug...
      

  7.   

    看到nullable的基础类型就觉的那啥以前见过一家伙最喜欢把bool弄成bool?,美其名曰【要考虑null的情况】太2了。。
      

  8.   


    如果你能从界面功能和业务逻辑分开的角度考察问题,你才能体会这样写的好处。
    WPF的很多优势需要你在使用了MVVM之后才能发现,Behavior是对MVVM的一个小小补充,在你深入WPF之后,你会发现你很少会在XAML中写事件。
      

  9.   

    当你阅读量足够的时候,你会发现无论是优秀的开源代码,还是Framework本身,都会使用这种方式来解决类似的问题。
      

  10.   


    是,如果用MVVM,确实非常方便。所以我对#13楼的实现方法打算加以吸收采纳。可是你#11楼的做法呢,既没沾上MVVM的光,也没我的传统方法简洁,属于两头都没占着呀。不过你的写法也算提醒了我可以用Behavior来实现,虽然不打算采用你的实现,但还是在此表示感谢了。
      

  11.   


    MVVM 是非常棒的界面编程设计模式,很多情况下我们都希望用它,但它也不是唯一的设计模式。虽然我界面编程经验并不多,但你也不能说别人没有用MVVM那么别人就是菜鸟,写的代码就不高效。所有的架构模式的目的都是合理地解耦,使代码可测试。MVC、MVP、MVVM,在实际中都有它自己的适用场景。
      

  12.   


    MVVM在实践中会有所缺陷,有一部分问题解决不了,一般是用Behavior的形式解决。
    况且这个问题完全可以理解为纯界面问题,如非特别需要,一般不需要“侵入”VM中的代码。
      

  13.   


    不怎么来CSDN了,很多人不怎么认识,仅就代码论代码
      

  14.   

    public class RadioButtonEx : RadioButton
        {
            protected override void OnClick(EventArgs e)
            {
                if (this.Checked)
                {
                    this.Checked = false;
                }
                else
                {
                    base.OnClick(e);
                }
            }
        }在哪写不是写
    WinForm就一个写代码的地
    没争论
      

  15.   

    总之,MVVM我会多做尝试。但是目前我手头有一个项目是基于MVP模式的,呵呵。多谢30楼的解答。