Before the AutoComplete Behaviour retrieves any data, it fires a Populating event. The comments at the top of the raisePopulating method are helpful:
I just followed the instructions provided therein. I created a function called onPopulating to handle the populating event:
As instructed above, the onPopulating function first cancels the populating event with the set_cancel method. The text entered in the textbox associated with the AutoComplete behaviour is contained in the behaviour’s _currentPrefix property. There seems to be no public method to access the contents of that property. The get_completionSetCount method returns the number of items that should be returned by the web service – or, in this case, by the data service. I wanted to return from the database Sessions whose names contained the current prefix. To do this, I needed to use the filter parameter of the query string. Numerous operators can be used within the filter parameter, and they are briefly described on the Using Microsoft ADO.NET Data Services page on MSDN. The operator I needed was substringof, which takes two parameters, the string to be searched for, and the database field to be searched in. In this case, I was searching for the Prefix text in the Name field. The top parameter has been discussed in a previous post. I set it to the completionSetCount. Finally, I set the final parameter of the fetchData method, the userContext, to the current Prefix, as this will be needed later.
Assuming the call to the Data Service succeeds, we arrive at the ACSucceeded function:
The purpose of this function is convert the data from the Data Service into a form suitable for the Auto Complete Behaviour’s _update method, which the comments in the raisePopulating method said had to be called. This _update method takes three parameters: first, a string containing the text sent to the Data Service, which we have passed to ACSucceeded in the context parameter; second, an array of strings, which contains the results from the data source; and third, a Boolean specifying whether these results should be cached. The strings in the array of results can either be standard text or JSON strings. If a string is JSON, it can have either one or two properties; and if it has two, the first is the text that will be displayed in the Auto Complete drop-down, and the second is the value associated with that text, which can be retrieved when, for example, the Auto Complete’s ItemSelected event is raised. In our case, we simply construct an array of strings containing the names of the sessions that fulfilled the search criteria.
Behaviours that are added to elements with a DataView seem to be removed whenever the DataView is bound to a new object. I therefore decided to attach the AutoComplete behaviour in the PopupShowing function, after the details DataView is bound to data:
Once or twice, the AutoComplete was not removed when expected. This might suggest a bug, but I have covered it up by testing for the existence of the AutoComplete before adding another. This needs further investigation. I set the serviceMethod and service Path to ‘Dummy,’ as the populating event was not raised when either was left null or empty.
We have now enabled the user to select the name of an existing session and then associate a session of that name with a presenter. With the application in its current state, however, a new session is still added to the database, whereas we want the presenter to be associated with the existing session. To accomplish this, we need to check, when a session is added to a presenter, whether the session is new, or whether it already exists in the database. The method I have used to perform this check is less than ideal, but is satisfactory in the circumstances.
When the Add button is clicked, and the onSessionCommand function is called, we now test whether a Session with the added name already exists. This test is carried out in the FindSession function, which is discussed below. If there is no such Session, a new one is created in the way described in the previous post. If, however, such a Session does exist, there only needs to be created a new Link, which is then associated with the existing Session.
The FindSession function simply runs through all the items in the DataContext, checking first whether its type is Sessions, and then whether its name is the same as the name that was passed in as the function’s parameter:
If it finds such a Session, it returns it. Otherwise, it returns null.
The details view with AutoComplete in action:
Now that one Session can belong to several Presenters, deletion presents a problem. The database will not allow a record to be deleted if it is related to a record in another table. In fact, the database enforces the very behaviour we want. One presenter, for example, might well decide to pull out of giving a session, and leave his partner to give it alone. On the other hand, we probably would not want a session to exist without a presenter, since a session without a presenter is not a session at all. Well, I suppose one might as well say that a presenter without a session is not a presenter at all. Nevertheless, for this application I have decided to delete any session not associated with a presenter. In the onSessionCommand function, I call the Data Service to determine how many presenters are associated with a given session:
I have used the datacontext’s fetchDeferredProperty method to retrieve the Links property of the appropriate Session. I have passed as userContext an object containing a reference to the Dataview and to the chosen session, as these will be needed in the deleteSession function, where the necessary deletions happen:
If the Session Links property contains more than one item, only the Link from the current Presenter to the Session is deleted. Otherwise, both the Link and the Session are deleted, as before.