2015-02-05 5 views
0

WPF의 KeyBinding 바인딩에 문제가 있습니다. MVVM 패턴과 WPF를 사용하여 .net 3.5 프로젝트를 개발 중입니다. 나는 어떤 편지가 타이프 될 때마다 명령을 발사해야한다. 불행히도 Command 및 CommandParameter는이 .net 버전에서는 종속성 속성이 아니며 바인딩 할 수 없습니다. 따라서 뷰 모델에서 명령 및 명령 매개 변수를 할당하기 위해 첨부 된 속성을 작성했습니다. 하지만 그들에게 바인딩이 작동하지 않습니다, 나는 (명령 매개 변수에서) 텍스트 바인딩을 변경할 때 CommandBindingParameterChanged가 상승하지만 매개 변수에 바인딩이있을 때는 그렇지 않습니다. 나는 창의 이름을 정하고 구속력있게 전달하는 것에 지쳤지만, 또한 효과가 없었다. 그러나 버튼에 동일한 명령을 할당하면 잘 동작합니다.KeyBinding의 연결된 속성 바인딩

첨부 성질 : : 여기 내 코드입니다

public class Helper 
{ 
    public static readonly DependencyProperty CommandBindingProperty = DependencyProperty.RegisterAttached("CommandBinding", typeof(ICommand), typeof(Helper), new FrameworkPropertyMetadata(default(ICommand), FrameworkPropertyMetadataOptions.None, CommandChanged)); 

    public static ICommand GetCommandBinding(DependencyObject o) 
    { 
     return (ICommand)o.GetValue(CommandBindingProperty); 
    } 
    public static void SetCommandBinding(DependencyObject o, ICommand value) 
    { 
     o.SetValue(CommandBindingProperty, value); 
    } 

    private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var input = d as InputBinding; 

     input.Command = (ICommand)e.NewValue; 
    } 


    public static readonly DependencyProperty CommandBindingParameterProperty = DependencyProperty.RegisterAttached("CommandBindingParameter", typeof(object), typeof(Helper), new PropertyMetadata(CommandParameterChanged)); 

    private static void CommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var input = d as InputBinding; 
     if (input != null) 
      input.CommandParameter = e.NewValue; 
    } 
    public static object GetCommandBindingParameter(DependencyObject o) 
    { 
     return o.GetValue(CommandBindingParameterProperty); 
    } 
    public static void SetCommandBindingParameter(DependencyObject o, object value) 
    { 
     o.SetValue(CommandBindingParameterProperty, value); 
    } 
} 

뷰 모델이

public class MainWindowViewModel : ViewModelBase 
{ 

    private string _text; 

    public string Text 
    { 
     get { return _text; } 
     set 
     { 
      _text = value; 
      RaisePropertyChanged("Text"); 
     } 
    } 


    private bool _parameter; 
    public bool Parameter 
    { 
     get { return _parameter; } 
     set 
     { 
      _parameter = value; 
      RaisePropertyChanged("Parameter"); 
     } 
    } 

    public MainWindowViewModel() 
    { 
     Parameter = true; 
    } 

    private RelayCommand<bool> _someCommand; 

    public ICommand SomeCommand 
    { 
     get { return _someCommand ?? (_someCommand = new RelayCommand<bool>(Execute, CanExecute)); } 
    } 

    private bool CanExecute(bool arg) 
    { 
     return arg; 
    } 

    private void Execute(bool obj) 
    { 
     //do something 
    } 
} 

XAML :

<Window x:Class="Test.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525" 
    xmlns:local="clr-namespace:Test" 
    Name="Window" 
    DataContext="{Binding Main, Source={StaticResource Locator}}" 
    > 
<Grid> 
    <StackPanel> 
     <TextBox Text="{Binding Text}"> 
      <TextBox.InputBindings> 
       <KeyBinding Key="A" local:Helper.CommandBinding="{Binding DataContext.SomeCommand, ElementName=Window}" local:Helper.CommandBindingParameter="{Binding DataContext.Parameter, ElementName=Window}"/> 
      </TextBox.InputBindings> 
     </TextBox> 
     <Button Content="SomeButton" Command="{Binding SomeCommand}" CommandParameter="{Binding Parameter}"/> 
    </StackPanel> 
</Grid> 

답변

0

이 솔루션을 시도 할 수 있습니다.

블렌드 3 상호 작용을 사용합니다. 즉, System.Windows.Interactivity를 & Microsoft.Expression.Interactions.dll을 프로젝트에 대한 참조로 사용합니다. 아래 변경 사항을 테스트했습니다. (뷰 모델에서 정의 된) 실행 방법은, 이동 텍스트 박스가 키 입력된다라고

수정 XAML :.

<Window x:Class="Test.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525" 
    xmlns:local="clr-namespace:Test" 
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
    Name="Window"> 
    <Window.DataContext> 
     <local:MainWindowViewModel/> 
    </Window.DataContext> 
    <Grid> 
     <StackPanel> 
      <TextBox> 
       <i:Interaction.Triggers> 
        <i:EventTrigger EventName="KeyUp"> 
         <local:CommandAction Command="{Binding Path=SomeCommand}" CommandParameter="{Binding Path=Parameter}" /> 
        </i:EventTrigger> 
       </i:Interaction.Triggers> 
      </TextBox> 
     </StackPanel> 
    </Grid> 
</Window> 

CommandAction.CS 대신 헬퍼,의 commandAction를 사용한다. 의 commandAction는 this location

using System; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Input; 
using Microsoft.Expression.Interactivity; 
using System.Windows.Interactivity; 

namespace Test 
{ 
    /// <summary> 
    /// The CommandAction allows the user to route a FrameworkElement's routed event to a Command. 
    /// For instance this makes it possible to specify--in Xaml--that right-clicking on a Border 
    /// element should execute the Application.Close command (this example may not make much sense, 
    /// but it does illustrate what's possible). 
    /// 
    /// CommandParameter and CommandTarget properties are provided for consistency with the Wpf 
    /// Command pattern. 
    /// 
    /// The action's IsEnabled property will be updated according to the Command's CanExecute value. 
    /// 
    /// In addition a SyncOwnerIsEnabled property allows the user to specify that the owner element 
    /// should be enabled/disabled whenever the action is enabled/disabled. 
    /// </summary> 
    public class CommandAction : TargetedTriggerAction<FrameworkElement>, ICommandSource 
    { 
     #region Properties to Expose 
     [Category("Command Properties")] 
     public ICommand Command 
     { 
      get { return (ICommand)GetValue(CommandProperty); } 
      set { SetValue(CommandProperty, value); } 
     } 

     public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
      "Command", typeof(ICommand), typeof(CommandAction), new PropertyMetadata(
       (ICommand)null, OnCommandChanged)); 

     [Category("Command Properties")] 
     public object CommandParameter 
     { 
      get { return (object)GetValue(CommandParameterProperty); } 
      set { SetValue(CommandParameterProperty, value); } 
     } 

     public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
      "CommandParameter", typeof(object), typeof(CommandAction), new PropertyMetadata()); 

     [Category("Command Properties")] 
     public IInputElement CommandTarget 
     { 
      get { return (IInputElement)GetValue(CommandTargetProperty); } 
      set { SetValue(CommandTargetProperty, value); } 
     } 

     public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
      "CommandTarget", typeof(IInputElement), typeof(CommandAction), new PropertyMetadata()); 

     [Category("Command Properties")] 
     public bool SyncOwnerIsEnabled 
     { 
      get { return (bool)GetValue(SyncOwnerIsEnabledProperty); } 
      set { SetValue(SyncOwnerIsEnabledProperty, value); } 
     } 

     /// <summary> 
     /// When SyncOwnerIsEnabled is true then changing CommandAction.IsEnabled will automatically 
     /// update the owner (Target) IsEnabled property. 
     /// </summary> 
     public static readonly DependencyProperty SyncOwnerIsEnabledProperty = DependencyProperty.Register(
      "SyncOwnerIsEnabled", typeof(bool), typeof(CommandAction), new PropertyMetadata()); 

     #endregion 

     #region Command implementation 

     /// <summary> 
     /// This is a strong reference to the Command.CanExecuteChanged event handler. The commanding 
     /// system uses a weak reference and if we don't enforce a strong reference then the event 
     /// handler will be gc'ed. 
     /// </summary> 
     private EventHandler CanExecuteChangedHandler; 

     private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var action = (CommandAction)d; 
      action.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue); 
     } 

     private void OnCommandChanged(ICommand oldCommand, ICommand newCommand) 
     { 
      if (oldCommand != null) 
       UnhookCommand(oldCommand); 
      if (newCommand != null) 
       HookCommand(newCommand); 
     } 

     private void UnhookCommand(ICommand command) 
     { 
      command.CanExecuteChanged -= CanExecuteChangedHandler; 
      UpdateCanExecute(); 
     } 

     private void HookCommand(ICommand command) 
     { 
      // Save a strong reference to the Command.CanExecuteChanged event handler. The commanding 
      // system uses a weak reference and if we don't save a strong reference then the event 
      // handler will be gc'ed. 
      CanExecuteChangedHandler = new EventHandler(OnCanExecuteChanged); 
      command.CanExecuteChanged += CanExecuteChangedHandler; 
      UpdateCanExecute(); 
     } 

     private void OnCanExecuteChanged(object sender, EventArgs e) 
     { 
      UpdateCanExecute(); 
     } 

     private void UpdateCanExecute() 
     { 
      if (Command != null) 
      { 
       RoutedCommand command = Command as RoutedCommand; 
       if (command != null) 
        IsEnabled = command.CanExecute(CommandParameter, CommandTarget); 
       else 
        IsEnabled = Command.CanExecute(CommandParameter); 
       if (Target != null && SyncOwnerIsEnabled) 
        Target.IsEnabled = IsEnabled; 
      } 
     } 

     #endregion 

     protected override void Invoke(object o) 
     { 
      if (Command != null) 
      { 
       var command = Command as RoutedCommand; 
       if (command != null) 
        command.Execute(CommandParameter, CommandTarget); 
       else 
        Command.Execute(CommandParameter); 
      } 
     } 
    } 
} 

스크린 샷에서 발견된다 : System.Windows.Interactivity & Microsoft.Expression.Interactions.dll 사용자 환경에서 누락 된 경우, 조화를 설치하십시오. 블렌드는 매우 쉽고 설치에는 많은 시간이 걸리지 않습니다.

Screenshot