仅在外部事件上更改切换按钮/单选按钮状态

时间:2011-04-14 07:56:46

标签: wpf binding radio-button state togglebutton

我想呈现几个ToggleButton / RadioButton元素:

  1. 映射到枚举,这意味着DataContext具有“公共模式CurrentMode”属性。
  2. 互斥(只选中一个按钮)
  3. 单击按钮时,状态不会立即更改。而是将请求发送到服务器。当响应到来时,状态会发生变化。
  4. 为已选中/未选中状态设置不同的图像
  5. 例如,4个按钮将显示以下视图模型:

    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");
        }
    }
    

    我最初的方法是使用How to bind RadioButtons to an enum?中的解决方案,但这还不够,因为按钮状态会立即更改,即使我没有在setter中调用NotifyPropertyChanged。另外,我不喜欢“GroupName”黑客。

    有什么想法吗?我不介意创建一个自定义按钮类,因为我需要很多按钮来表示多个视图。

    我正在使用.NET 3.5 SP1和VS2008。

1 个答案:

答案 0 :(得分:0)

如果你想使用RadioButtons,你只需要做一些小的调整来解决RadioButton的默认行为。

您需要解决的第一个问题是RadioButtons基于其常见的直接父容器自动分组。由于你不喜欢“GroupName”hack,你的另一个选择是将每个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, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Active}">Active</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked="{Binding Path=CurrentMode, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Disabled}">Disabled</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked="{Binding Path=CurrentMode, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Running}">Running</RadioButton>
        </Grid>
    </StackPanel>

这使我进入下一个解决方法,即确保点击的按钮在点击之后不会保持在Checked状态,这是为了触发set调用,因为你绑定了IsChecked属性。您需要发送一个额外的NotifyPropertyChanged,但必须将其推送到Dispatch线程的队列中,以便该按钮将接收通知并更新其可视化IsChecked绑定。将它添加到您的ViewModel类,它可能会替换您现有的NotifyPropertyChanged实现,我假设您的类正在实现问题代码中缺少的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线程的线程上进行的。

最后,如果您希望它们具有不同的Checked / Unchecked外观,则需要将样式应用于RadioButtons。快速谷歌搜索WPF RadioButton ControlTemplate最终提出了这个网站:http://madprops.org/blog/wpf-killed-the-radiobutton-star/