Нажатие клавиши в текстовом поле MVVM

Смотрите на Счетный. Метод SequenceEqual

var dictionary = new Dictionary() {{1, "a"}, {2, "b"}};
var intList = new List {1, 2};
var stringList = new List {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);

13
задан Lee Treveil 11 November 2009 в 00:33
поделиться

4 ответа

Я испытал подобное поведение Позсара. И его ответ сработал для меня лучше, чем нормальная svn diff-сила. Однако при работе на DOS-машине (например, через Cygwin) может потребоваться несколько изменить его ответ. Следующий diff + патч работал для исправления моих текстовых + двоичных файлов в Cygwin с помощью --binary arg:

svn diff --force --diff-cmd /usr/bin/diff -x "-au --binary" OLD-URL NEW-URL > mybinarydiff.diff

patch -p0 --binary -i mybinarydiff.diff
-121--2246061-

Как сказал Wsanville, вы не можете использовать класс. Но обычное наследование CSS действительно работает - скажем, если ваш html был

<div class="border">
    <div id="foo">
       hello
    </div>
    <div id="bar">
       world
    </div>
</div>

Вы можете сказать

.border {border: 1px solid #f00;}
#foo {border:inherit;}

Что в некоторых случаях может быть достаточно хорошо

-121--4859509-

Превосходный WPF рамки Caliburn прекрасно решает эту проблему.

        <TextBox cm:Message.Attach="[Gesture Key: Enter] = [Action Search]" />

Синтаксис [Action Search] связывается с методом в модели представления. Нет нужды в ICommands вообще.

6
ответ дан 1 December 2019 в 22:57
поделиться

Возможно, самым простым переходом от обработки событий кода программной части к командам MVVM были бы триггеры и действия из Expression Blend Samples .

Вот фрагмент кода, демонстрирующий, как можно обработать событие нажатия клавиши внутри текстового поля с помощью команды:

    <TextBox>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="KeyDown">
                <si:InvokeDataCommand Command="{Binding MyCommand}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>
4
ответ дан 1 December 2019 в 22:57
поделиться

Лучшим вариантом, вероятно, было бы использовать для этого Присоединенное свойство . Если у вас есть Blend SDK, класс Behavior значительно упростит это.

Например, было бы очень легко изменить это TextBox Behavior , чтобы запускать ICommand при каждом нажатии клавиши вместо нажатия кнопки Enter.

1
ответ дан 1 December 2019 в 22:57
поделиться

Прежде всего , если вы хотите привязать RoutedUICommand, это просто - просто добавьте в коллекцию UIElement.InputBindings:

<TextBox ...>
  <TextBox.InputBindings>
    <KeyBinding
      Key="Q"
      Modifiers="Control" 
      Command="my:ModelAirplaneViewModel.AddGlueCommand" />

Проблемы начинаются, когда вы пытаетесь установить Command = "{Binding AddGlueCommand}", чтобы получить ICommand из ViewModel. Поскольку Command не является DependencyProperty, вы не можете установить для него Binding.

Возможно, вашей следующей попыткой будет создание присоединенного свойства BindableCommand, имеющего PropertyChangedCallback, обновляющее Command. Это позволяет вам получить доступ к привязке, но нет возможности использовать FindAncestor для поиска вашей ViewModel, поскольку коллекция InputBindings не устанавливает InheritanceContext.

Очевидно, вы можете создать присоединенное свойство, которое можно применить к TextBox, которое будет пройти через все InputBindings, вызывая BindingOperations.GetBinding для каждого, чтобы найти привязки команд и обновить эти привязки с явным источником, что позволит вам сделать это:

<TextBox my:BindingHelper.SetDataContextOnInputBindings="true">
  <TextBox.InputBindings>
    <KeyBinding
      Key="Q"
      Modifiers="Control" 
      my:BindingHelper.BindableCommand="{Binding ModelGlueCommand}" />

Это присоединенное свойство было бы легко реализовать: на PropertyChangedCallback он запланировал бы «обновление» "в DispatcherPriority.Input и настройте событие, чтобы" обновление "переназначалось при каждом изменении DataContext. Затем в коде «обновления» просто установите DataContext для каждой привязки InputBinding:

...
public static readonly SetDataContextOnInputBindingsProperty = DependencyProperty.Register(... , new UIPropetyMetadata
{
   PropertyChangedCallback = (obj, e) =>
   {
     var element = obj as FrameworkElement;
     ScheduleUpdate(element);
     element.DataContextChanged += (obj2, e2) =>
     {
       ScheduleUpdate(element);
     };
   }
});
private void ScheduleUpdate(FrameworkElement element)
{
  Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
  {
    UpdateDataContexts(element);
  })
}

private void UpdateDataContexts(FrameworkElement target)
{
  var context = target.DataContext;
  foreach(var inputBinding in target.InputBindings)
    inputBinding.SetValue(FrameworkElement.DataContextProperty, context);
}

Альтернативой двум присоединенным свойствам могло бы быть создание подкласса CommandBinding, который получает маршрутизируемую команду и активирует связанную команду:

<Window.CommandBindings>
  <my:CommandMapper Command="my:RoutedCommands.AddGlue" MapToCommand="{Binding AddGlue}" />
  ...

в этом случае InputBindings в каждом объекте будет ссылаться на маршрутизируемую команду, а не на привязку. Затем эта команда будет направлена ​​в представление и сопоставлена.

Код для CommandMapper относительно тривиален:

public class CommandMapper : CommandBinding
{
  ... // declaration of DependencyProperty 'MapToCommand'

  public CommandMapper() : base(Executed, CanExecute)
  {
  }
  private void Executed(object sender, ExecutedRoutedEventArgs e)
  {
    if(MapToCommand!=null)
      MapToCommand.Execute(e.Parameter);
  }
  private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
  {
    e.CanExecute =
      MapToCommand==null ? null :
      MapToCommand.CanExecute(e.Parameter);
  }
}

На мой вкус, я бы предпочел использовать решение с прикрепленными свойствами, так как это не так много кода и сохраняет мне не пришлось объявлять каждую команду дважды (как RoutedCommand и как свойство моей ViewModel). Вспомогательный код встречается только один раз и может использоваться во всех ваших проектах.

С другой стороны, если вы делаете только разовый проект и не ожидаете повторного использования чего-либо, возможно, даже CommandMapper будет излишним. Как вы упомянули,

9
ответ дан 1 December 2019 в 22:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: