【问题标题】:Revert ToggleButton IsChecked state after user taps it用户点击后恢复 ToggleButton IsChecked 状态
【发布时间】:2019-11-13 10:21:29
【问题描述】:

假设您想要一个与 VCR 或便携式录音机播放控件等效的 UI。您可以有几个状态:播放、快进/快退、停止等。您可以将这些状态表示为切换按钮,并且您希望以 MVVM 方式执行此操作,因此您将绑定IsChecked。在我的特殊情况下,我们选择将IsChecked 绑定为OneWay,并将Tapped 事件绑定到(视图)模型上的方法。 Tapped 事件处理程序是当用户请求状态更改(即要执行的操作)时实际工作的内容。

在您尝试立即撤消请求的操作或状态更改之前,这一切都很好。以磁带为例,假设我想倒带或播放,但播放器中没有磁带。按钮需要在视觉上保持在停止状态,而不是播放/倒带状态。我们无法禁用按钮,因为我们告诉用户为什么在他们尝试执行操作时无法执行操作。

为了实现这一点,我想我可以简单地提高 PropertyChanged 并让按钮重新评估它们的状态。不工作。即使我在等待异步调用以显示模式后通知,它也不起作用。使用SelectedItem 将其实现为重新模板化的ItemsControl 并没有更好的效果。似乎没有办法拦截事件并将其标记为已处理。我不想诉诸 Task.Delay 诡计。我还有什么其他选择?我可以使用标准 Button 实现单独的按钮样式/状态并完全丢弃 ToggleButtons,但我很好奇这是否会对自动化 UI 测试或可访问性产生某种影响。

【问题讨论】:

    标签: c# uwp


    【解决方案1】:

    如果您有TappedEventHandler,那么您实际上可以使用来自发件人的IsChecked 并恢复状态。

        private void ToggleButton_Tapped(object sender, RoutedEventArgs e)
        {
            if(NoCasette == true)
            (sender as ToggleButton).IsChecked = false;            
        }
    

    【讨论】:

    • 在之前的这个问题的实例中,我直接绑定到一个视图模型方法。在这种情况下,它是一个可重用的控件,可以直接访问这些 UI 元素,所以......这很简单而且很有效。让我觉得问起来有点傻。
    【解决方案2】:

    在您尝试立即撤消请求的操作或状态更改之前,这一切都很好。

    根据您的描述,您的代码可能如下所示:

    public async Task Start()
    {
        await DoSomething()
        IsChecked = true;
    }
    

    当任务中断或快速切换时,不能保证按钮的状态会改变。

    我的建议是使用VisualStateManager将按钮的可视化表示与逻辑代码分开,以保证按钮的即时响应。

    首先创建一个名为VCRButtonGroups

    UserControl

    VCRButtonGroups.xaml

    <Grid>
        <StackPanel Orientation="Horizontal">
            <ToggleButton Content="Pause" x:Name="PauseButton" Tapped="PauseButton_Tapped"/>
            <ToggleButton Content="Start" x:Name="StartButton" Margin="15,0,0,0" Tapped="StartButton_Tapped"/>
    
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup>
                    <VisualState x:Name="Pause">
                        <VisualState.Setters>
                            <Setter Target="StartButton.IsChecked" Value="False"/>
                            <Setter Target="PauseButton.IsChecked" Value="True"/>
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState x:Name="Start">
                        <VisualState.Setters>
                            <Setter Target="StartButton.IsChecked" Value="True"/>
                            <Setter Target="PauseButton.IsChecked" Value="False"/>
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
    
        </StackPanel>
    </Grid>
    

    VCRButtonGroups.xaml.cs

    private void PauseButton_Tapped(object sender, TappedRoutedEventArgs e)
    {
        VisualStateManager.GoToState(this, "Pause",false);
        // Do other
    }
    
    private void StartButton_Tapped(object sender, TappedRoutedEventArgs e)
    {
        VisualStateManager.GoToState(this, "Start", false);
        // Do other
    }
    

    这只是一个带有两个按钮的示例,您可以根据此代码添加新按钮。这样做的好处是可以预设一组状态,然后根据不同的触发条件进入不同的状态,保证UI可以正确显示。

    最好的问候。

    【讨论】:

      猜你喜欢
      • 2010-12-04
      • 2021-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 2014-06-05
      • 2020-06-17
      • 1970-01-01
      相关资源
      最近更新 更多