ActionMessage in XAML

Feb 10, 2011 at 9:50 PM

Hello,

I am attempting to execute a function in my Viewmodel based on a trigger set on a TextBox (this is capturing the KeyDown event for me in my viewmodel):

<TextBox x:Name="QuickSearch" Text="" Width="200">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="KeyDown" >                                               
         <cal:ActionMessage MethodName="QuickSearchKeyDown" >
              <cal:Parameter Value="$eventArgs"/>
         </cal:ActionMessage>
     </i:EventTrigger>
   </i:Interaction.Triggers>
</TextBox>

My intention is to execute a coroutine when the Enter key is detected:

 public IEnumerable<IResult> QuickSearchKeyDown(KeyEventArgs args)
 {
    if (args.Key == Key.Enter)
        return ExecuteQuickSearch();
    else
        return null;           
 }
public IEnumerable<IResult> ExecuteQuickSearch()
{
    yield return Show.Busy();

    var _query = new SearchQuery();
    int empNumber;
    if (int.TryParse(QuickSearch, out empNumber))
        _query.EmployeeNumber = empNumber;
    _query.FirstName = QuickSearch;
    _query.LastName = QuickSearch;
    _query.DataSet = 0;
    _query.IsQuickSearch = true;
    
    var _search = _query.AsResult();
    yield return _search;

    _activeResultSet = _search.Response;
    SearchResultCollection = new ObservableCollection<EmployeeGridRow>();
    foreach (var result in _activeResultSet)
    {
        SearchResultCollection.Add(new EmployeeGridRow
        {
            EmployeeId = result.EmployeeHeader.EmployeeId,
            EmployeeNumber = result.EmployeeHeader.EmployeeNumber,
            FirstName = result.EmployeeHeader.FirstName,
            LastName = result.EmployeeHeader.LastName
        });
    }

    yield return Show.NotBusy();

}

The "yield return _search" executes a method in my RIAbackend that replies with an IEnumerable<Iresult>:

public void Handle(SearchQuery search, Action<IEnumerable<SearchResult>> reply)
{
    var riaQuery = _context.GetEmployeeHeadersQuery().Where(t => t.DataSet == search.DataSet);

    if (search.IsQuickSearch)
    {
        if (search.EmployeeNumber != null)
            riaQuery = riaQuery.Where(t => t.EmployeeNumber == search.EmployeeNumber || t.LastName == search.LastName || t.FirstName == search.FirstName);
        else
            riaQuery = riaQuery.Where(t => t.LastName == search.LastName || t.FirstName == search.FirstName);
    }
    else
    {
        if (search.EmployeeNumber != null)
            riaQuery = riaQuery.Where(t => t.EmployeeNumber == search.EmployeeNumber);
        if (search.FirstName != null)
            riaQuery = riaQuery.Where(t => t.FirstName == search.FirstName);
        if (search.LastName != null)
            riaQuery = riaQuery.Where(t => t.LastName == search.LastName);
    }

    _context.Load(riaQuery, (loadOP) => { }, null).Completed += (s, pe) =>
        {
            reply
            (
                from emp in ((LoadOperation<EmployeeHeader>)s).Entities
                select new SearchResult
                {
                    EmployeeHeader = emp
                }
            );
        };
}

The ExecuteQuickSearch method is also bound to a button in my xaml. When I execute the function from the button, everything works as advertised. When I execute it from the KeyDown event however, the coroutine does not yield its results, it continues processing before my backend method has finished and replied. Is there something I am missing with the ActionMessage code in the xaml?

Thanks!
Jason
Feb 11, 2011 at 9:39 AM
Edited Feb 11, 2011 at 9:41 AM

Seems strange, indeed. 
Could you please check or post the code of the IResult implementation returned by "AsResult" extension method? 
I would like check if under some circumstances the IResult.Completed event could be called before the actual completion of the RIA call.
That event is used by CM to advance in the coroutine evaluation and processing.

I can't understand, however, how could it behave differently with a Button.Click trigger...

 

(edit: sorry for multiple posts, experiencing network problems)

Feb 11, 2011 at 9:39 AM
Edited Feb 11, 2011 at 9:40 AM

-

Feb 11, 2011 at 9:39 AM
Edited Feb 11, 2011 at 9:40 AM

-

Feb 11, 2011 at 2:14 PM

Hi Marco - 

Thank you for the response, but I figured out the issue.

It was happening because my query parameters were not being updated to the values the user provided. The text in the TextBox control was not being committed to the

ViewModel until after focus left the TextBox (I commented out the TextChanged event in ConventionManager.ApplySilverlightTriggers method). It worked for the button since focus left the TextBox and committed the text.

I reimplemented the ConventionManager code like this:

var textBox = element as TextBox;
if (textBox != null && dependencyProperty == TextBox.TextProperty)
{
    //textBox.TextChanged += delegate { expressionSource(textBox).UpdateSource(); };
    textBox.KeyDown += (s, args) =>
    {
        if (args.Key == System.Windows.Input.Key.Enter)
            expressionSource(textBox).UpdateSource();
    };

    textBox.GotFocus += delegate { textBox.SelectAll(); };
        
    return;
}

Actually, you pointed me in the right direction as I started digging in the invocation code in the backend that calls the RIA method and saw the old values :) I'm still relatively new to async 

programming and didn't think to check the values given the behavior I was seeing.

Thanks for your help!