2015-10-16 117 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} –