如何解决在 GotFocus 事件中为 ToggleButton 设置 IsChecked 的 IsChecked 导致
本文关键字:IsChecked ToggleButton 设置 事件 导致 GotFocus 何解决 解决 | 更新日期: 2023-09-27 18:24:13
要求
当用户按 Tab 键转到其中一个切换按钮时,我希望选中它并取消选中任何其他切换按钮。 如果用户单击切换按钮,其状态应从选中更改为未选中或未选中更改为选中。
问题
在ToggleButton
的 GotFocus
事件中设置 IsChecked
属性会导致调用Checked
事件,然后神秘地取消选中ToggleButton
并导致调用Unchecked
事件。
法典
下面是我的实验室项目中演示这一点的示例代码。
XAML:
<Grid>
<StackPanel x:Name="ToggleButtonContainer" Orientation="Horizontal" VerticalAlignment="Top">
<ToggleButton Content="Toggle 1" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<ToggleButton Content="Toggle 2" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<ToggleButton Content="Toggle 3" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<ToggleButton Content="Toggle 4" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<ToggleButton Content="Toggle 5" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
</StackPanel>
</Grid>
法典:
private void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("INFO: ToggleButton_Checked called by {0}", sender);
foreach (var toggleButton in ToggleButtonContainer.Children)
{
if (toggleButton != sender &&
(toggleButton as ToggleButton).IsChecked.HasValue &&
(toggleButton as ToggleButton).IsChecked.Value)
{
(toggleButton as ToggleButton).IsChecked = false;
}
}
}
private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("INFO: ToggleButton_Unchecked called by {0}", sender);
}
private void ToggleButton_GotFocus(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("INFO: ToggleButton_GotFocus called by {0}", sender);
(sender as ToggleButton).IsChecked = true;
}
环境信息
- Visual Studio 2013 Update 4
- 视窗 8/视窗 10
- .NET Framework 4.5
观察
我观察到,如果我在释放鼠标左键之前单击按钮并拖离它,那么我就不会遇到这个问题。 当您调试并单步执行 Checked
事件时,也会发生这种情况(因为同样,自调试器获取焦点以来,ToggleButton
永远不会收到 MouseLeftButtonUp
事件(。
问题
- 为什么按钮变为未选中状态?
- 这是 WPF 中的错误还是我只是做错了什么? 解决此问题
- 的好方法是什么? (如果有良好、干净的解决方法(
让我知道这是否适合您。
XAML
<Grid>
<StackPanel x:Name="ToggleButtonContainer" Orientation="Horizontal" VerticalAlignment="Top">
<RadioButton Style="{StaticResource {x:Type ToggleButton}}" Content="Toggle 1" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<RadioButton Style="{StaticResource {x:Type ToggleButton}}" Content="Toggle 2" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<RadioButton Style="{StaticResource {x:Type ToggleButton}}" Content="Toggle 3" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<RadioButton Style="{StaticResource {x:Type ToggleButton}}" Content="Toggle 4" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
<RadioButton Style="{StaticResource {x:Type ToggleButton}}" Content="Toggle 5" Margin="2" Padding="4" GotFocus="ToggleButton_GotFocus" Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked" />
</StackPanel>
</Grid>
法典:
private void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("INFO: ToggleButton_Checked called by {0}", sender);
}
private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("INFO: ToggleButton_Unchecked called by {0}", sender);
}
private void ToggleButton_GotFocus(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("INFO: ToggleButton_GotFocus called by {0}", sender);
(sender as ToggleButton).IsChecked = true;
}
为什么按钮变为未选中状态?
该按钮变为未选中状态,因为 IsChecked
属性在 GotFocus
事件中已更改,但在触发 OnClick
方法时又更改回来。
这是 WPF 中的错误还是我只是做错了什么?
似乎当前的 ToggleButton 的设计目的是选择/取消选择它的唯一控件位于鼠标左键单击或空格键上。
解决此问题的好方法是什么?(如果有良好、干净的解决方法(
感谢这篇文章和与Janne Matikainen的对话,我能够提出以下解决方案:
public class MyToggleButton : ToggleButton
{
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
if (e.KeyboardDevice.IsKeyDown(Key.Tab))
{
IsChecked = true;
base.OnGotKeyboardFocus(e);
}
}
protected override void OnLostFocus(System.Windows.RoutedEventArgs e)
{
IsChecked = false;
base.OnLostFocus(e);
}
}
将
使用 GroupName 属性可实现切换控件之间的互斥。
<StackPanel>
<RadioButton GroupName="Os" Content="Windows XP" IsChecked="True"/>
<RadioButton GroupName="Os" Content="Windows Vista" />
<RadioButton GroupName="Os" Content="Windows 7" />
<RadioButton GroupName="Office" Content="Microsoft Office 2007" IsChecked="True"/>
<RadioButton GroupName="Office" Content="Microsoft Office 2003"/>
<RadioButton GroupName="Office" Content="Open Office"/>
</StackPanel>
你可以通过简单的风格来做到这一点。为了测试目的,我将Margin
设置为5
切换按钮是否checked
;如果得到focused
则将控件设置为 checked
并将Foreground
设置为 Red
.
<Style TargetType="ToggleButton" >
<Setter Property="IsChecked" Value="False" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Margin" Value="5" />
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="IsChecked" Value="True" />
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>