仅在外部事件上才更改ToggleButton / RadioButton状态

问题描述

|| 我想介绍几个ToggleButton / RadioButton元素,这些元素是: 映射到一个枚举,这意味着DataContext具有\“ public Mode CurrentMode \”属性。 互斥(仅选中一个按钮) 单击按钮后,状态不会立即更改。而是将请求发送到服务器。响应到达时状态发生变化。 对于已检查/未检查状态有不同的图像 例如,四个按钮将显示以下视图模型:
public class viewmodel
{
    public enum Mode { Idle,Active,disabled,Running }
    Mode m_currentMode = Mode.Idle;

    public Mode CurrentMode
    {
        get { return m_currentMode; }
        set
        {
            SendRequest(value);
        }
    }

    // Called externally after SendRequest,not from UI
    public void ModeChanged(Mode mode)
    {
        m_currentMode = mode;
        NotifyPropertyChanged(\"CurrentMode\");
    }
}
我最初的方法是使用“如何将RadioButtons绑定到枚举?”中的解决方案,但这还不够,因为即使我没有在setter中调用NotifyPropertyChanged,按钮的状态也会立即更改。另外,我不喜欢\“ GroupName \”骇客。 有任何想法吗?我不介意创建自定义按钮类,因为我需要多个按钮来实现多个视图。 我正在使用.NET 3.5 SP1和VS2008。     

解决方法

如果要使用RadioButton,则只需做一些细微调整即可解决RadioButton的默认行为。 您需要解决的第一个问题是根据单选按钮的公共直接父容器对单选按钮进行自动分组。由于您不喜欢\“ GroupName \”,因此您的另一选择是将每个RadioButton置于其自己的Grid或其他容器中。这将使每个按钮成为其自己的组的成员,并将迫使它们根据其IsChecked绑定进行行为。
    <StackPanel Orientation=\"Horizontal\">
        <Grid>
            <RadioButton IsChecked=\"{Binding Path=CurrentMode,Converter={StaticResource enumBooleanConverter},ConverterParameter=Idle}\">Idle</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked=\"{Binding Path=CurrentMode,ConverterParameter=Active}\">Active</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked=\"{Binding Path=CurrentMode,ConverterParameter=Disabled}\">Disabled</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked=\"{Binding Path=CurrentMode,ConverterParameter=Running}\">Running</RadioButton>
        </Grid>
    </StackPanel>
这使我进入下一个解决方法,即确保单击的按钮在单击后不会保持其“已检查”状态,这是触发设置调用所必需的,因为您绑定了IsChecked属性。您将需要发送一个附加的NotifyPropertyChanged,但必须将其推送到Dispatch线程的队列中,以便该按钮将接收通知并更新其可视的IsChecked绑定。将此添加到您的ViewModel类中,这可能会替换您现有的NotifyPropertyChanged实现,并且我假设您的类正在实现INotifyPropertyChanged,该INotifyPropertyChanged在问题的代码中丢失:
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            Dispatcher uiDispatcher = Application.Current != null ? Application.Current.Dispatcher : null;
            if (uiDispatcher != null)
            {
                uiDispatcher.BeginInvoke(DispatcherPriority.DataBind,(ThreadStart)delegate()
                    {
                        PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
                    });
            }
        }
    }
然后在CurrentMode \的Setter中调用NotifyPropertyChanged(\“ CurrentMode \”)。您可能已经需要这样的东西,因为您服务器的ModeChanged调用可能是在不是Dispatcher线程的线程上传入的。 最后,如果您希望单选按钮具有不同的选中/未选中外观,则需要对它们应用样式。 Google最终通过此网站对WPF RadioButton ControlTemplate进行了快速的Google搜索:http://madprops.org/blog/wpf-killed-the-radiobutton-star/。