2015-10-16 119 views
1

我想在WPF中实现一个拨号程序。我有一个窗口,里面有一个用户控件。用户控件有很多按钮,但用户也可以使用数字键输入数字。WPF UserControl,带按钮和KeyBindings

我创建了一个小样本项目,以显示我在哪里:

MainWindow.xaml

<Window x:Class="wpf_dialer.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:wpf_dialer" 
     Title="MainWindow" Height="200" Width="525"> 
    <Window.Resources> 
    <local:DialerViewModel x:Key="myViewModel" /> 
    </Window.Resources> 
    <Grid DataContext="{StaticResource myViewModel}"> 
    <local:Dialer /> 
    </Grid> 
</Window> 

Dialer.xaml

<UserControl x:Class="wpf_dialer.Dialer" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:wpf_dialer" 
      mc:Ignorable="d" 
      d:DesignHeight="200" d:DesignWidth="300" 
      d:DataContext="{d:DesignInstance local:DialerViewModel}" 
      Loaded="UserControl_Loaded"> 
    <UserControl.InputBindings> 
    <KeyBinding Key="A" Command="{Binding CommandDialValue, Mode=OneTime}" CommandParameter="." /> 
    <KeyBinding Key="Back" Command="{Binding CommandDialValue, Mode=OneTime}" CommandParameter="Back" /> 
    <KeyBinding Key="Enter" Command="{Binding CommandAcceptValue, Mode=OneTime}" CommandParameter="KeyBinding" /> 
    </UserControl.InputBindings> 
    <UniformGrid Columns="1"> 
    <TextBox IsEnabled="False" Text="{Binding DialedValue, Mode=OneWay}" MinWidth="200" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10"/> 
    <Button Content="OK" Margin="60,30" Command="{Binding CommandAcceptValue, Mode=OneTime}" CommandParameter="Button" /> 
    </UniformGrid> 
</UserControl> 

DialerViewModel.cs

using System; 
using System.ComponentModel; 
using System.Windows.Input; 

namespace wpf_dialer 
{ 
    class DialerViewModel : INotifyPropertyChanged 
    { 
     private Random RAND = new Random(); 
     private string _dialed_value = "00"; 
     public string DialedValue 
     { 
      get { return _dialed_value; } 
      set 
      { 
       if (_dialed_value == value) return; 
       _dialed_value = value; 
       RaisePropertyChanged("DialedValue"); 
      } 
     } 

     public ICommand CommandDialValue { get { return new CommandImpl(DialValue); } } 
     public ICommand CommandAcceptValue { get { return new CommandImpl(Alert); } } 

     private void DialValue(object parameter) 
     { 
      if (parameter.ToString() == "Back") 
      { 
       if (DialedValue.Length > 0) 
       { 
        DialedValue = DialedValue.Substring(0, DialedValue.Length - 1); 
       } 
      } 
      else 
      { 
       DialedValue += RAND.Next(0, 10).ToString(); 
      } 
     } 

     private void Alert(object parameter) 
     { 
      System.Windows.MessageBox.Show(parameter.ToString()); 
     } 

     #region INotifyPropertyChanged 

     protected void RaisePropertyChanged(string property_name) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(property_name)); 
      } 
     } 
     public event PropertyChangedEventHandler PropertyChanged; 
     #endregion 

     private class CommandImpl : ICommand 
     { 
      private readonly Action<object> _action = null; 
      public CommandImpl(Action<object> action) 
      { 
       _action = action; 
      } 

      public event EventHandler CanExecuteChanged; 
      public bool CanExecute(object parameter) { return true; } 
      public void Execute(object parameter) { _action(parameter); } 
     } 
    } 
} 

目标:

  • 一旦被加载的窗口中,当用户按下一个键时,CommandDialValue执行;
  • 当用户按输入时,将显示一个带有文本“KeyBinding”的消息框。 CommandAcceptValue必须从KeyBinding中调用,而不是从按钮中调用;

问题:

  • 当加载窗口,设定的按键不执行。当我单击UserControl中的某个按钮时,它们会被执行;

  • 当我按Enter键时,按钮的命令被执行,但我希望用户控件的KeyBinding被执行;

  • 此拨号程序必须保存在UserControl(或ControlTemplate或DataTemplate)中,因为它包含在一个非常复杂的窗口中。

  • 我不想把KeyBindings放在Window上,因为那时UserControl是不可重用的,因为它的DataContext和用户控件不一样。

UPDATE:

我通过对所有的按钮设定Focusable="False"解决的第二个问题。

回答

1

为了防止按钮获得焦点,我为所有按钮设置了Focusable="False"

要在窗口打开时设置焦点,我在UserControl上设置了Focusable="True",并在Loaded事件上调用了Focus()

Dialer.xaml

   d:DataContext="{d:DesignInstance local:DialerViewModel}" 
      Loaded="UserControl_Loaded" Focusable="True"> 
    <UserControl.InputBindings> 

Dialer.xaml.cs

private void UserControl_Loaded(object sender, RoutedEventArgs e) { 
    Focus(); 
} 

我没有发现FocusManager.FocusedElement组合工作。我试过{Binding ElementName=myUserControl}{Binding RelativeSource={RelativeSource Self}}

2

这是一个焦点问题。当您的窗口第一次加载时,您的用户控件没有焦点。所以键绑定的手势不会拦截你的按键。在第一次应用加载时,您可以将焦点集中到用户控件上。 (Focusable =“True”(我不知道这是否有帮助,但我确定FocusManager会有帮助))。然后你的关键手势会运作良好。

+0

你能更精确吗?我在UserControl上试过'FocusManager.FocusedElement =“{Binding RelativeSource = {RelativeSource Mode = Self}}”'但它没有帮助。 – DonkeyMaster

+0

给你一个X:Name属性= CustomName,然后FocusManager.FocusedElement =“{Binding ElementName = CustomName} –