我有一个用户控件,它是使用Prism组成的应用程序的一部分。它有这个'后退'按钮:
<Button Content="Back"
Command="{Binding BackCommand}"
Padding="5 12 5 2" />
有时此按钮不会执行命令。视图模型提供此命令:
public class BackCommand : ICommand
{
private readonly IInterviewController _controller;
public BackCommand(IInterviewController controller)
{
_controller = controller;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_controller.MovePreviousTopic();
}
public event EventHandler CanExecuteChanged;
}
此外,用户控件具有“下一步”按钮,该按钮根据用户在第二个控件中选择的内容,通过一系列分支问题移动用户。后退按钮应该将用户带到上一个问题。后退按钮通常执行绑定命令,因此我知道绑定有效。有时用户必须先单击后退按钮两次才能触发命令。我将CanExecute主体替换为始终返回true(如上所示)仍然按钮停止工作。
我在按钮上放置了临时事件处理程序,并发现当命令执行失败时:
关于SO的每个问题我发现命令没有触发,OP有一个问题或另一个绑定命令。由于我的命令受到限制,我发现它并没有多大用处。
编辑#2:我发现了问题的原因。组成应用程序的组件之一是试图控制焦点。要重现此问题,请将其粘贴到窗口中:
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Current count:"/>
<TextBlock Text="{Binding Counter}"/>
</StackPanel>
<CheckBox x:Name="MyCheckbox" IsChecked="{Binding MaintainFocus}" LostFocus="MaintainFocus" >Maintain Focus</CheckBox>
<Button Command="{Binding MyCommand}" Content="Test" Width="100" />
</StackPanel>
将其粘贴到后面的窗口代码中: public partial class MainWindow:Window { 私有只读ViewModel _vm;
public MainWindow()
{
DataContext = _vm = new ViewModel();
InitializeComponent();
}
private void MaintainFocus(object sender, RoutedEventArgs e)
{
if (_vm.MaintainFocus)
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Input,
new Action(() => MyCheckbox.Focus()));
}
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
MyCommand = new TestCommand(this);
}
public ICommand MyCommand { get; set; }
private int _counter;
public int Counter
{
get { return _counter; }
set
{
_counter = value;
OnPropertyChanged();
}
}
public bool MaintainFocus { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TestCommand : ICommand
{
private readonly ViewModel _viewModel;
public TestCommand(ViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_viewModel.Counter++;
}
public event EventHandler CanExecuteChanged;
}
现在,如果您选中Maintain Focus复选框,则不会触发Test按钮。
答案 0 :(得分:2)
我的问题的解决方法是不允许Button获得焦点:
<Button Command="{Binding MyCommand}"
Focusable="False"
Content="Test"
Width="100" />
如果按钮在执行命令之前失去焦点,那么对于WPF的ICommand来说似乎是一个问题,但是如果按钮永远不会在第一时间获得焦点则不会。
我很幸运,通过控件上的Tab Navigation提供了这些按钮的功能,因此我不需要重构代码设置焦点。由于UI设计师不希望在按钮上显示键盘焦点,因此这是我书中的双赢。
我遇到的一个初步问题是如何调试此问题。我从来没有得到合适的答案,所以我将在下面总结我的流程:
Debug.WriteLine("<something meaningful>");
添加到因鼠标单击而调用的每个事件/方法。这告诉我什么事件在起作用,哪些事件没有和顺序。它没有真正的帮助。也许这将有助于将来。
答案 1 :(得分:0)
点击Image
会引发Click
事件。但是,如果您设置Padding
属性并在实际Image
之外单击,则不会引发Click
事件。
您可以将Border
元素放在Grid
背景为Transparent
的情况下解决此问题:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<Border BorderThickness="0"
Background="Transparent"
Margin="{TemplateBinding Control.Padding}">
<Image Name="Image"
Source="{Binding NormalImage, RelativeSource={RelativeSource TemplatedParent}}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed"
Value="True">
<Setter TargetName="Image"
Property="Source"
Value="{Binding PressedImage, RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
但请注意,在提问时,您应始终提供Minimal, Complete, and Verifiable example个问题。