Over the past 5 months we have been prototyping GWT and setting up the infrastructure. WE are using GXT for the widgets with MVP and Command Pattern implementations. However, we are currently looking to do a spike on a ComboBox with autosuggest from a live Database. I would like to do this in the framework of the MVP and Command pattern implementations. Any one out there have any ideas how to go about doing this?
I solved that using a generic DispatchDataProxy modelled over the Command Pattern. Thanks for the link, but GXT documentation leaves a lot to be desired, though the framework is really nice and cool.
I will post the code here `public class DispatchDataProxy implements DataProxy> {
#Inject
private DispatchAsync dispatch ;//= new StandardDispatchAsync(new DefaultExceptionHandler());
#Override
public void load(DataReader<ListLoadResult<X>> reader, Object loadConfig, final AsyncCallback<ListLoadResult<X>> callback) {
if (loadConfig instanceof BasePagingLoadConfig) {
BasePagingLoadConfig a = (BasePagingLoadConfig) loadConfig;
Map<String, Object> map = a.getProperties();
Object data = map.get("query");
XCommand action = new XCommand();
action.setX((String) data);
dispatch.execute(action, new AsyncCallback<XResult>() {
#Override
public void onFailure(Throwable arg0) {
//Log.debug("Some error:" + arg0.getMessage());
callback.onFailure(arg0);
}
#Override
public void onSuccess(XResult arg0) {
ListLoadResult<X> list = arg0.getList();
callback.onSuccess(list);
}
});
}
}
public DispatchAsync getDispatch() {
return dispatch;
}
public void setDispatch(DispatchAsync dispatch) {
this.dispatch = dispatch;
}
}`
Hope its useful. Will appreciate some comments as well
Have you looked here?
http://www.sencha.com/examples-2/explorer.html#advancedcombobox
They show something similar. The issue with GXT is you are better off using their DataProxy because you need to set a ModelData instance.
I found solution for simple combo box, override getValue method:
public SimpleComboBox<String> createEditableSimpleComboBox() {
return new SimpleComboBox<String>() {
#Override
public SimpleComboValue<String> getValue() {
SimpleComboValue<String> v = super.getValue();
String raw = getRawValue();
if ((v == null || v.getValue() == null) && raw != null && !raw.isEmpty()) {
v = new SimpleComboValue<String>(raw){
private static final long serialVersionUID = 1L;
};
}
return v;
}
};
}
Now when you add to combo box default value (not defined in store) method getValue returns this value - not null.
Related
As I see error in my code when I did Binding with DelegateCommand. in its Method I called 1 asyc service which is calling arcgis server to find the City names on using Task Service.
I'm bothered about Prism 4.1 Support async? If not is there any work around?
public DelegateCommand SearchCitiesCommand;
private PlaceFinderService placeFinderService;
public GenericMapViewModel()
{
HelloMapMessage = "Generic Map Pow Pow !!";
placeFinderService = new PlaceFinderService();
SearchCitiesCommand = DelegateCommand. //new DelegateCommand(Search);
}
public virtual async Task Search()
{
List<Graphic> graphics=await placeFinderService.FindAsync(SearchText);
SearchResults = graphics;
}
ASYN service
public class PlaceFinderService
{
TaskCompletionSource<List<Graphic>> tcs;
public Task<List<Graphic>> FindAsync(String searchText)
{
FindParameters findParams = new FindParameters();
findParams.LayerIds.AddRange(new int[] { 0 }); // cities layer
findParams.SearchFields.AddRange(new string[] { "CITY_NAME" });
findParams.SpatialReference = new SpatialReference(4326);
findParams.SearchText = searchText;
FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer");
tcs = new TaskCompletionSource<List<Graphic>>();
findTask.ExecuteCompleted += FindTaskExecuteCompleted;
findTask.Failed += findTaskFailed;
return tcs.Task;
}
private void findTaskFailed(object sender, TaskFailedEventArgs e)
{
tcs.TrySetResult(new List<Graphic>());
}
private void FindTaskExecuteCompleted(object sender, FindEventArgs e)
{
List<Graphic> graphics = new List<Graphic>();
foreach (var result in e.FindResults)
{
graphics.Add(result.Feature);
}
tcs.TrySetResult(graphics);
}
}
I see few http://prismwindowsruntime.codeplex.com/discussions/535816 but I think its Prism 5.
To my knowledge, no MVVM framework supports "async commands". IMO, this is because there are lots of different semantic possibilities.
I have an MSDN article that you may find helpful. It provides a few ideas (and example implementations) but at the end of the day you'll have to craft your own "AsyncCommand" because the exact semantics will depend on your application's needs.
I have the following class that I use in order to populate a combo box:
public class DamageTypeList
{
static Begbil2Entities _DB = new Begbil2Entities();
public static List<HUB_DamageTypes> _list = (from d in _DB.HUB_DamageTypes orderby d.DamageOrder select d).ToList();
public static List<HUB_DamageTypes> TList
{
get
{
return _list;
}
}
}
In the xaml file I add it like this:
<UserControl.Resources>
<me:DamageTypeList x:Key="DamageTypeList"/>
The xaml line creates an error (ONLY in design time, it runs pefectly at runtime):
Cannot create an instance of "DamageTypeList". C:\HUB\HUB\HubbCostOfferPage.xaml
I have found some suggestions to solve it by using:
if (!DesignerProperties.IsInDesignTool)
But how do I use it to solve my problem?
You can use the flag DesignerProperties.IsInDesignTool to prevent the DB creation and to use hardcoded entities in your list.
public class DamageTypeList
{
static Begbil2Entities _DB;
public static List<HUB_DamageTypes> _list;
public static Begbil2Entities DB
{
get
{
if(_DB == null && !DesignerProperties.IsInDesignTool)
_DB = new Begbil2Entities();
return _DB;
}
}
public static List<HUB_DamageTypes> TList
{
get
{
if(_list == null)
{
if(!DesignerProperties.IsInDesignTool)
_list = (from d in DB.HUB_DamageTypes orderby d.DamageOrder select d).ToList();
else
_list = new List<HUB_DamageTypes>(){
// Initialize it with hardcoded values
};
}
return _list;
}
}
}
Before doing that, tough, I would investigate a little further what is the cause of the design-time exception, as #fhlamarche suggested. You can try to debug the design time execution, is not that hard. See this link.
The designer attempts to call the default constructor but your class doesn't have one.
You just need to add a private or internal default constructor to your class.
I'm using Spring AOP trying to define a good approach to have all my tables audited with no much hassle. Example of scenario:
I have a table named Person and its respective table PersonLog, which will store the Person values in addition to the user who modified, when and the type of the event, for each update.
Simply put, my question is:
I'm trying to come up with a way that my advice class would be smart enough to handle any new table being audited without any needed modification to it... let's say that I created the table Car and its CarLog table, if I could avoid the need to change anything in my advice implementation (it would automatically identify Car as being audited and would be able to persist a CarLog entity) ---> I can identify table Car as being audited pretty easily (by annotation), but I'm struggling to find a way to create and persist a CarLog instance dynamically.
Can anyone think of a way to accomplish that? Thanks.
This is called "change data capture" or CDC.
Personally, I don't think this is a good use for Spring or AOP. I think it would be better done in the database itself, especially if the database is shared/modified by more than one application.
You don't say which database you're using, but I'd recommend digging into your vendor's docs to find out what they have out of the box to support CDC.
i had similiar requirement in project where i am suppose to take snapshot of complex object graph before saving.
solution i have applied is 1) developed custom annotation #Archivable with certain attribute like nullify,ignore, orignal, setArchiveFlag
2) written hiberante deep cloner utility which create replica of object and insert into same table. deep cloner works on simple trick searlize and then desearlize object this will create new instances and then set id and version to null.
3) used cloner utility in entity interceptor to take decision weather to archive or not.
below is some of that code.
#Retention(RetentionPolicy.RUNTIME)
#Target( { ElementType.TYPE })
public #interface Archivable {
/** This will mark property as null in clone */
public String[] nullify() default {};
/**
* If property is archivable but not from enclosing entity then specify as
* ignore.
*/
public String[] ignore() default {};
/**
* sets original reference to clone for back refer data. This annotation is
* applicable to only root entity from where archiving started.
*
* #return
*/
public String original() default "";
/**
* if marks cloned entity to archived, assumes flag to be "isArchived".
* #return
*/
public boolean setArchiveFlag() default false;
}
#Component
public class ClonerUtils {
private static final String IS_ARCHIVED = "isArchived";
#Autowired
private SessionFactory sessionFactory;
public Object copyAndSave(Serializable obj) throws Exception {
List<BaseEntity> entities = new ArrayList<BaseEntity>();
Object clone=this.copy(obj,entities);
this.save(clone, entities);
return clone;
}
public Object copy(Serializable obj,List<BaseEntity> entities) throws Exception{
recursiveInitliaze(obj);
Object clone = SerializationHelper.clone(obj);
prepareHibernateObject(clone, entities);
if(!getOriginal(obj).equals("")){
PropertyUtils.setSimpleProperty(clone, getOriginal(obj), obj);
}
return clone;
}
private void save(Object obj,List<BaseEntity> entities){
for (BaseEntity baseEntity : entities) {
sessionFactory.getCurrentSession().save(baseEntity);
}
}
#SuppressWarnings("unchecked")
public void recursiveInitliaze(Object obj) throws Exception {
if (!isArchivable(obj)) {
return;
}
if(!Hibernate.isInitialized(obj))
Hibernate.initialize(obj);
PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
for (PropertyDescriptor propertyDescriptor : properties) {
Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
if (origProp != null && isArchivable(origProp) && !isIgnore(propertyDescriptor, obj)) {
this.recursiveInitliaze(origProp);
}
if (origProp instanceof Collection && origProp != null) {
for (Object item : (Collection) origProp) {
this.recursiveInitliaze(item);
}
}
}
}
#SuppressWarnings("unchecked")
private void prepareHibernateObject(Object obj, List entities) throws Exception {
if (!isArchivable(obj)) {
return;
}
if (obj instanceof BaseEntity) {
((BaseEntity) obj).setId(null);
((BaseEntity) obj).setVersion(null);
if(hasArchiveFlag(obj)){
PropertyUtils.setSimpleProperty(obj, IS_ARCHIVED, true);
}
entities.add(obj);
}
String[] nullifyList = getNullifyList(obj);
for (String prop : nullifyList) {
PropertyUtils.setProperty(obj, prop, null);
}
PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
for (PropertyDescriptor propertyDescriptor : properties) {
if (isIgnore(propertyDescriptor, obj)) {
continue;
}
Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
if (origProp != null && isArchivable(origProp)) {
this.prepareHibernateObject(origProp, entities);
}
/** This code is for element collection */
if(origProp instanceof PersistentBag){
Collection elemColl=createNewCollection(origProp);
PersistentBag pColl=(PersistentBag) origProp;
elemColl.addAll(pColl.subList(0, pColl.size()));
PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), elemColl);
continue;
}
if (origProp instanceof Collection && origProp != null) {
Collection newCollection = createNewCollection(origProp);
PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), newCollection);
for (Object item : (Collection) origProp) {
this.prepareHibernateObject(item, entities);
}
}
}
}
#SuppressWarnings("unchecked")
private Collection createNewCollection(Object origProp) {
try {
if(List.class.isAssignableFrom(origProp.getClass()))
return new ArrayList((Collection)origProp);
else if(Set.class.isAssignableFrom(origProp.getClass()))
return new HashSet((Collection)origProp);
else{
Collection tempColl=(Collection) BeanUtils.cloneBean(origProp);
tempColl.clear();
return tempColl;
}
} catch (Exception e) {
e.printStackTrace();
}
return new ArrayList();
}
private boolean isIgnore(PropertyDescriptor propertyDescriptor,Object obj){
String propertyName=propertyDescriptor.getName();
String[] ignores=getIgnoreValue(obj);
return ArrayUtils.contains(ignores, propertyName);
}
private String[] getIgnoreValue(Object obj) {
String[] ignore=obj.getClass().getAnnotation(Archivable.class).ignore();
return ignore==null?new String[]{}:ignore;
}
private String[] getNullifyList(Object obj) {
String[] nullify=obj.getClass().getAnnotation(Archivable.class).nullify();
return nullify==null?new String[]{}:nullify;
}
public boolean isArchivable(Object obj) {
return obj.getClass().isAnnotationPresent(Archivable.class);
}
private String getOriginal(Object obj) {
String original=obj.getClass().getAnnotation(Archivable.class).original();
return original==null?"":original;
}
private boolean hasArchiveFlag(Object obj) {
return obj.getClass().getAnnotation(Archivable.class).setArchiveFlag();
}
#SuppressWarnings({ "unchecked", "unused" })
private Collection getElemColl(Object obj, Object origProp) {
Collection elemColl=createNewCollection(origProp);
for (Object object : (Collection)origProp) {
elemColl.add(object);
}
return elemColl;
}
#SuppressWarnings("unused")
private boolean isElementCollection(Object obj, String name) {
try {
Annotation[] annotations=obj.getClass().getDeclaredField(name).getAnnotations();
for (Annotation annotation : annotations) {
if(annotation.annotationType() == ElementCollection.class)
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
Envers is what you require for auditing purposes
I want to define a SuggestBox, which behaves like the search bar in Google Maps: When you begin to type, real addresses, starting with the typed letters, appear.
I think, that I need to use the Geocoder.getLocations(String address, LocationCallback callback) method, but I have no idea how to connect this with the oracle, which is needed by the suggest box to produce its suggestions.
Can you please give me ideas how do I connect the getLocations Method with the SuggestOracle?
I solved this by implementing a subclass of SuggestBox, which has it's own SuggestOracle. The AddressOracle deals as a Wrapper for the Google Maps Service, for which the class Geocoderin the Google Maps API for GWT offers abstractions.
So here is my solution:
First we implement the Widget for a SuggestBox with Google Maps suggestions
public class GoogleMapsSuggestBox extends SuggestBox {
public GoogleMapsSuggestBox() {
super(new AddressOracle());
}
}
Then we implement the SuggestOracle, which wraps the Geocoder async method abstractions:
class AddressOracle extends SuggestOracle {
// this instance is needed, to call the getLocations-Service
private final Geocoder geocoder;
public AddressOracle() {
geocoder = new Geocoder();
}
#Override
public void requestSuggestions(final Request request,
final Callback callback) {
// this is the string, the user has typed so far
String addressQuery = request.getQuery();
// look up for suggestions, only if at least 2 letters have been typed
if (addressQuery.length() > 2) {
geocoder.getLocations(addressQuery, new LocationCallback() {
#Override
public void onFailure(int statusCode) {
// do nothing
}
#Override
public void onSuccess(JsArray<Placemark> places) {
// create an oracle response from the places, found by the
// getLocations-Service
Collection<Suggestion> result = new LinkedList<Suggestion>();
for (int i = 0; i < places.length(); i++) {
String address = places.get(i).getAddress();
AddressSuggestion newSuggestion = new AddressSuggestion(
address);
result.add(newSuggestion);
}
Response response = new Response(result);
callback.onSuggestionsReady(request, response);
}
});
} else {
Response response = new Response(
Collections.<Suggestion> emptyList());
callback.onSuggestionsReady(request, response);
}
}
}
And this is a special class for the oracle suggestions, which just represent a String with the delivered address.
class AddressSuggestion implements SuggestOracle.Suggestion, Serializable {
private static final long serialVersionUID = 1L;
String address;
public AddressSuggestion(String address) {
this.address = address;
}
#Override
public String getDisplayString() {
return this.address;
}
#Override
public String getReplacementString() {
return this.address;
}
}
Now you can bind the new widget into your web page by writing the following line in the onModuleLoad()-method of your EntryPoint-class:
RootPanel.get("hm-map").add(new GoogleMapsSuggestBox());
I am trying to make a call to a wcf service with my silverlight application and I am having some trouble understanding how the model returns the result back to the view model. Within my view model I have the following command:
public DelegateCommand GetSearchResultCommand
{
get
{
if (this._getSearchResultCommand == null)
this._getSearchResultCommand = new DelegateCommand(GetSearchResultCommandExecute, CanGetSearchResultsCommandExecute);
return this._getSearchResultCommand;
}
}
private void GetSearchResultCommandExecute(object parameter)
{
this.SearchResults = this._DataModel.GetSearchResults(this.SearchTerm);
}
/// <summary>
/// Bindable property for SearchResults
/// </summary>
public ObservableCollection<QueryResponse> SearchResults
{
get
{
return this._SearchResults;
}
private set
{
if (this._SearchResults == value)
return;
// Set the new value and notify
this._SearchResults = value;
this.NotifyPropertyChanged("SearchResults");
}
}
then within my model I have the following code
public ObservableCollection<QueryResponse> GetSearchResults(string searchQuery)
{
//return type cannot be void needs to be a collection
SearchClient sc = new SearchClient();
//******
//TODO: stubbed in placeholder for Endpoint Address used to retreive proxy address at runtime
// sc.Endpoint.Address = (clientProxy);
//******
sc.QueryCompleted += new EventHandler<QueryCompletedEventArgs>(sc_QueryCompleted);
sc.QueryAsync(new Query { QueryText = searchQuery });
return LastSearchResults;
}
void sc_QueryCompleted(object sender, QueryCompletedEventArgs e)
{
ObservableCollection<QueryResponse> results = new ObservableCollection<QueryResponse>();
results.Add(e.Result);
this.LastSearchResults = results;
}
When I insert breakpoints within the model I see where the query is being executed and a result is returned within the model (this.LastSearchResults = results) however I cannot seem to get this collection to update/ notify the view model of the result. I've generated and run a similar test using just a method and dummy class and it seems to work so I suspect the issue is due to the async call /threading. I have INotifyPropertyChanged within the ViewModel to sync the View and ViewModel. Do I need to also implement INotifyPropChng within the model as well? I'm new to mvvm so any help / example of how I should approach this would be appreciated.
Thank you,
UPDATE
In further testing I added INotifyPropertyChanged to the model and changed the Completed event as follows:
void sc_QueryCompleted(object sender, QueryCompletedEventArgs e)
{
ObservableCollection<QueryResponse> results = new ObservableCollection<QueryResponse>();
results.Add(e.Result);
//this.LastSearchResults = results;
SearchResults = results;
}
Placing a watch on Search Results I now see it is updated with results from teh WCF. My question is still around is this teh correct approach? It seems to work right now however I am curious if I am missing something else or if I should not be placing INotify within the Model.
Thank you,
I've found that it's best to encapsulate my WCF services in an additional layer of Service classes. This allows me to more easily Unit Test my ViewModels. There are several patterns when doing this, though this is the simplest I've used. The pattern is to create a method that matches the definition of the service call, though also contains an Action that can be invoked after the service call completes.
public class Service : IService
{
public void GetSearchResults(string searchQuery, Action<ObservableCollection<QueryResponse>> reply)
{
//return type cannot be void needs to be a collection
SearchClient sc = new SearchClient();
//******
//TODO: stubbed in placeholder for Endpoint Address used to retreive proxy address at runtime
// sc.Endpoint.Address = (clientProxy);
//******
sc.QueryCompleted += (s,e) =>
{
ObservableCollection<QueryResponse> results = new ObservableCollection<QueryResponse>();
results.Add(e.Result);
reply(results);
};
sc.QueryAsync(new Query { QueryText = searchQuery });
}
}
You can also provide an interface that your ViewModel can use. This makes Unit Testing even easier, though is optional.
public interface IService
{
void GetSearchResults(string searchQuery, Action<ObservableCollection<QueryResponse>> reply);
}
Your ViewModel would then look something like this:
public class MyViewModel : INotifyPropertyChanged
{
private IService _service;
public MyViewModel()
: this(new Service())
{ }
public MyViewModel(IService service)
{
_service = service;
SearchResults = new ObservableCollection<QueryResponse>();
}
private ObservableCollection<QueryResponse> _searchResults
public ObservableCollection<QueryResponse> SearchResults
{
get { return _searchResults; }
set
{
_searchResults = value;
NotifyPropertyChanged("SearchResults");
}
}
public void Search()
{
_service.GetSearchResults("abcd", results =>
{
SearchResults.AddRange(results);
});
}
protected void NotifyPropertyChanged(string property)
{
var handler = this.PropertyChanged;
if(handler != null)
handler(new PropertyChangedEventArgs(property));
}
}
An additional reason for encapsulating your service calls into another class like this is that it can provide a single place for such things as logging and error handling. That way your ViewModel itself doesn't need to take care of those things specifically related to the Service.
I would likely use something along the lines of:
public class ViewModel : INotifyPropertyChanged
{
private readonly IModel model;
private readonly DelegateCommand getSearchResultsCommand;
public DelegateCommand GetSearchResultsCommand
{
get { return getSearchResultsCommand; }
}
public ObservableCollection<QueryResponse> SearchResults
{
get { return model.SearchResults; }
}
public ViewModel(IModel model)
{
this.model = model;
this.model.SearchResultsRetrieved += new EventHandler(model_SearchResultsRetrieved);
this.getSearchResultsCommand = new DelegateCommand(model.GetSearchResultCommandExecute, model.CanGetSearchResultsCommandExecute);
}
private void model_SearchResultsRetrieved(object sender, EventArgs e)
{
this.NotifyPropertyChanged("SearchResults");
}
}
public interface IModel
{
event EventHandler SearchResultsRetrieved;
void GetSearchResultCommandExecute(object parameter);
bool CanGetSearchResultsCommandExecute(object parameter);
ObservableCollection<QueryResponse> SearchResults { get; }
}
With the SearchResultsRetrieved event being fired by the Model when its SearchResults collection has been filled with the appropriate data. I prefer to have custom events rather than implement INotifyPropertyChanged on my models, particularly if there are only one, or a few, events that need to be communicated to the viewmodel.