Подтвердить что ты не робот

Caliburn Micro 'Enter' Ключевые события

Я пытаюсь связать событие с Caliburn Micro, и у меня возникают некоторые проблемы с получением правильных сообщений методу. Я хотел бы добавить возможность нажать клавишу 'Enter' после изменения значения в текстовом поле и выполнить тот же метод, к которому привязана кнопка рядом. Однако, независимо от того, какая клавиша нажата, я получаю следующие исключения:

Первое исключение исключения типа 'System.InvalidCastException' произошел в MyApp.exe

Первое случайное исключение типа 'System.Reflection.TargetInvocationException' произошел в mscorlib.dll

Первое случайное исключение типа "System.Reflection.TargetInvocationException" произошло в WindowsBase.dll

В предложении другого аналогичного вопроса Binding KeyDown Event Silverlight я попытался использовать ActionExecutionContext, но безрезультатно.

Вот xaml:

<TextBox Name="Threshold"                     
              Margin="5"
              Grid.Column="1"
              >
     <i:Interaction.Triggers>
         <i:EventTrigger EventName="KeyDown">
             <cal:ActionMessage MethodName="ExecuteFilterView">
                 <cal:Parameter Value="$executionContext"/>
             </cal:ActionMessage>
         </i:EventTrigger>
     </i:Interaction.Triggers>
</TextBox>

И метод:

 public void ExecuteFilterView(ActionExecutionContext context)
    {
        //Do stuff...
    }

Я понимаю, что я мог бы сэкономить себе некоторые головные боли и просто сделать стандартный обработчик событий в коде, но это приложение является упражнением в MVVM и учится использовать Caliburn.Micro, поэтому я хотел бы придерживаться этого конкретный подход.

Я просто пытаюсь отправить неверную информацию из мероприятия? Неужели мой xaml неправильно закодирован, чтобы получить то, что я хочу? Или я пропустил что-то еще?

4b9b3361

Ответ 1

Просто бросил тест вместе, обе эти работы для меня:

Использование полного синтаксиса:

    <TextBox Name="Threshold"                     
          Margin="5"
          Grid.Column="1">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="KeyDown">
                <cal:ActionMessage MethodName="ExecuteFilterView">
                    <cal:Parameter Value="$executionContext"/>
                </cal:ActionMessage>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>

Использование синтаксиса CM (предпочитайте это как можно более читаемым)

    <TextBox Name="Threshold"                     
          Margin="5"
          Grid.Column="1"
          cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($executionContext)]" />            

Это была тестовая VM:

public class MainWindowViewModel
{
    public void ExecuteFilterView(ActionExecutionContext context)
    { 
        // This method is hit and the context is present and correct
    }
}

Можете ли вы разместить свой полный код - вы уверены, что у вас правильно настроена структура? (вы следовали примеру запуска?

http://caliburnmicro.codeplex.com/wikipage?title=Basic%20Configuration%2c%20Actions%20and%20Conventions&referringTitle=Documentation

Edit:

Хорошо после вашего уточнения, я могу дать вам несколько примеров того, как это сделать - я расскажу вам свои личные предпочтения и почему, но выберите тот, который вам подходит лучше всего

  • Используя ActionExecutionContext и выставив eventargs:
    cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($executionContext)]"
    public void ExecuteFilterView(ActionExecutionContext context)
    {
        var keyArgs = context.EventArgs as KeyEventArgs;

        if (keyArgs != null && keyArgs.Key == Key.Enter)
        {
            // Do Stuff
        }
    }
  1. Использование EventArgs напрямую
    cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($eventArgs)]"
    public void ExecuteFilterView(KeyEventArgs keyArgs)
    {
        if (keyArgs.Key == Key.Enter)
        {
            // Do Stuff
        }
    }
  1. Мой личный фейв, создающий собственную запись словаря SpecialValues:

В вашем методе Bootstrapper.Configure...

MessageBinder.SpecialValues.Add("$pressedkey", (context) =>
{
    // NOTE: IMPORTANT - you MUST add the dictionary key as lowercase as CM
    // does a ToLower on the param string you add in the action message, in fact ideally
    // all your param messages should be lowercase just in case. I don't really like this
    // behaviour but that how it is!
    var keyArgs = context.EventArgs as KeyEventArgs;

    if (keyArgs != null)
        return keyArgs.Key;

    return null;
});

Ваше действие:

cal:Message.Attach="[Event KeyDown] = [Action ExecuteFilterView($pressedKey)]"

И код:

public void ExecuteFilterView(Key key)
{
    if (key == Key.Enter)
    {
        // Do Stuff
    }
}

Почему это мой любимый? Это означает, что ваша виртуальная машина просто получает нужное значение (большую часть времени вы не заботитесь о многих других параметрах), и вам не нужно знать, как или не использовать листинг eventargs - вы можете просто управлять по значению. Очевидно, используйте то, что лучше для вас

Также стоит отметить, что если у вас есть другие типы элементов управления, то подкласс KeyEventArgs будет работать для них. Если они не подклассы KeyEventArgs, но они все равно возвращают значение типа Key, это все равно будет работать, так как вы можете просто добавить еще один приведение в делегат, если первый не удался:

например.

MessageBinder.SpecialValues.Add("$pressedkey", (context) =>
{
    var keyArgs = context.EventArgs as KeyEventArgs;

    if (keyArgs != null)
        return keyArgs.Key;

    // Ok so it wasn't KeyEventArgs... check for some other type - maybe a 3rd party implementation
    var thirdPartyKeyArgs = context.EventArgs as ThirdPartyKeyArgs;

    if (thirdPartyKeyArgs != null)
        return thirdPartyKeyArgs.KeyProperty;

    return null;
});

Ответ 2

Если вы используете keyeventargs как тип параметра, и он возвращает u обратно null, тогда посмотрите на это: Вы можете использовать System.Windows.Forms.KeyEventArgs и KeyEventArgs, поскольку тип параметра ссылается на это, попробуйте с помощью System.Windows.Input.KeyEventArgs (он работает для меня).

public void ExecuteFilterView(System.Windows.Input.KeyEventArgs context)
{
     if(context.Key==System.Windows.Input.Key.Return)
     {
         //action here
     }      
}