Author |
Share Topic Topic Search Topic Options
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Topic: [SOLVED] ListConverterServiceBase Method Posted: 19-Oct-2007 at 12:25pm |
What does this method do?
AddListManager_KeepExistingEntitiesOnly(converter);
Edited by Linguinut - 23-Oct-2007 at 1:17pm
|
|
Bill Jensen
IdeaBlade
Joined: 31-Jul-2007
Location: United States
Posts: 229
|
Post Options
Quote Reply
Posted: 19-Oct-2007 at 2:30pm |
I concede--this is a rough neighborhood for walking the dog.
It adds a list manager to the EntityList of a ListConverter. It is invoked by the ListService (in the Cabana solution, Foundation module) when creating ListConverters for certain entity types.
It supplies the newly-created ListManager with a delegate to a predicate function that determines if a specific entity should be kept in the list.
This particular predicate function (IsExistingEntity) returns true only if the entity is either modified or unchanged and returns false if the entity is added or deleted.
I suspect Ward intended this as an example.
If you're calling this on your ListConverter, it might explain why your newly-added items don't show up.
On the other hand, this code also suggests how to add a ListManager to filter the entities contained in the list.
Bill J.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 19-Oct-2007 at 3:39pm |
Thanks for the info. I have employed this method a dozen times in the ListConverterService. The service is a good candidate for futher encapsulation. There is quite a bit of redundancy as time goes on.
Where is this method defined? I thought it should be in ListConverterServiceBase, but I do not see it in there. Actually, I can see it in the object browser, but not when I try to go to the definition itself. I'll open the LIB solution and see what I can find there. I am not sure how this usage suggests filtering is possible.
|
|
Bill Jensen
IdeaBlade
Joined: 31-Jul-2007
Location: United States
Posts: 229
|
Post Options
Quote Reply
Posted: 19-Oct-2007 at 4:29pm |
It IS in ListConverterServiceBase.
Be aware that the Go To Definition function won't navigate into the source files under ExternalSource in the Cabana solution since they are not built as part of this solution. They are there for reference only.
You could attach a ListManager to your List, passing a delegate to a different predicate--one that determines if the customer address is for the current customer, for example.
Bill J.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 19-Oct-2007 at 4:35pm |
The method is a protected static method of ListConverterServiceBase in IdeaBlade.Cab.UI.Services (hence, no "go to definition").
protected static void AddListManager_KeepExistingEntitiesOnly<T>(EntityListConverter<T> pListConverter) where T : Entity
{
EntityList<T> aList = (EntityList<T>) pListConverter.ListSource.List;
EntityListManager<T> listManager = new EntityListManager<T>(pListConverter.EntityManager.PersistenceManager, IsExistingEntity, null); // No hint available; DF can't listen for changes to RowState (yet).
aList.ListManager = listManager;
}
First of all...what is meant by "no hint available..."? Second, are you suggesting that another method could be created that would accept a filter parameter, but, obviously, do roughly the same thing? The IsExistingEntity would be replaced by a customer index, and the null would be replaced by the foreign key column name, right?
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 19-Oct-2007 at 4:43pm |
From the comments in the EntityListManager:
"The IdeaBlade.Persistence.EntityListManager<T>.Filter uses a .NET Predicate<T>, a delegate that defines a set of criteria and determines whether the specified object passed to it meets those criteria. The Filter receives every addition, deletion or modification (based on the IdeaBlade.Persistence.EntityListManager<T>.FilterColumns specified) of entities of the type watched, and determines whether the entity belongs in the list. If the Filter returns true the entity is added to or kept in the list; if the Filter returns false the entity is removed from the list. (Note that entities removed from the managed list are not removed from the PersistenceManager, nor are they deleted.) Performance will be needlessly poor if the EntityListManager tests an entity every time any of its columns change. To avoid this, specify in the constructor or the IdeaBlade.Persistence.EntityListManager<T>.FilterColumns property which entity columns are relevant to the filtering."
Once I unravel what this is saying, I think I could get this to work. Time to do a little homework on .NET Predicate<T>.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 20-Oct-2007 at 9:41am |
Interesting statement:
// Summary:
// Gets or sets the System.Predicate used to set filtering criteria for the
// list(s).
//
// Remarks:
// The filter should return true if the supplied Entity belongs in the list(s)
// managed.
// Setting or resetting the filter does not automatically refresh the list(s).
public Predicate<T> Filter { get; set; }
If the predicate changes, the list does not change. A list refresh will need to be provoked. Am I reading that correctly?
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 20-Oct-2007 at 10:19am |
Would this work in the ListConverterService?
protected void AddListManager_FilteredList<T>(EntityListConverter<T> pListConverter, int pFilter, EntityColumn pColumn) where T : Entity
{
mIndex = pFilter;
mColumn = pColumn;
EntityList<T> aList = (EntityList<T>)pListConverter.ListSource.List;
EntityListManager<T> listManager = new EntityListManager<T>
(pListConverter.EntityManager.PersistenceManager,
IsExistingEntity,
null);
aList.ListManager = listManager;
}
private bool IsExistingEntity<T>(T pEntity) where T : Entity
{
// Is the foreign key equal to the presented index
if (mIndex == (int)pEntity.GetColumnValue(mColumn.ColumnName)) { return true; };
return false;
}
private int mIndex = 0;
private EntityColumn mColumn;
How do I pass the index on which to filter the list? The ListConverterService takes no arguments.
Edited by Linguinut - 20-Oct-2007 at 10:35am
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 20-Oct-2007 at 10:45am |
Thinking about this again, I should be able to pass the column in order to create the EntityListManager. What is stumping me is this Predicate<T> animal. Even after reading and seeing other examples, I am not clear on how this thing works. The biggest question remains...how do I pass the parent entity index on which the child list is filtered? This seems so fundamental that there has to be a solution staring me in the face and I am just not seeing it.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 20-Oct-2007 at 2:49pm |
Here's a good article: http://msdn.microsoft.com/msdnmag/issues/06/09/AdvancedBasics/
Sure wished they taught this in kindergarten.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 22-Oct-2007 at 10:52am |
Well, I've been pondering, meditating and researching. I am more confused than ever. If someone could step in here and straighten out my thinking, I would really appreciate it.
|
|
Bill Jensen
IdeaBlade
Joined: 31-Jul-2007
Location: United States
Posts: 229
|
Post Options
Quote Reply
Posted: 22-Oct-2007 at 12:24pm |
Take heart, you're on the right track.
Your code is basically correct--I see you corrected the assignment in the conditional in the predicate.
A Predicate<T>() is just a delegate to a method that accepts a parameter of type T and returns a boolean. The method can determine its return value however it pleases.
Your remaining problem is "how does the ListConverterService, and hence the predicate, know what to compare against to decide if an entity should be included in the list?" From what I understand, you want the list (of customer addresses, for example) to track the currently selected item (e.g., customer) in some BindingSource<Customer> somewhere. Here are two possibilities:
1. In the module that owns the customer binding source, add it to the root workitem's Items collection (as early as possible so it's there when the ListConverterService needs it). Then, when asked for a CustomerAddressListConverter, the ListConverterService can retrieve it and supply it to the newly created CustomerListConverter.
Note that unlike Commands, Services, Workspaces, etc., the Items collection is not inherited from parent workitems. This means that
(a) You could add the BindingSource to the module's workitem if all requirements for synchronized list converters are contained within that module or
(b) You would need to add it to the root workitem if synchronization requirements cross module boundaries.
2. Modify your ListConverterService to implement an additional interface ISynchronizedListConverterService<T> with a single member that accepts a BindingSource<T>. This method merely stores the BindingSource in a member so it can be supplied to new ListConverters. Register your ListConverterService under this interface and inject it into the controller owning the customer binding source.
In any case, your list converter may need to attach to the CurrentChanged property of the binding source in order to refresh the list.
Hope this gets you moving.
Bill J.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 22-Oct-2007 at 2:14pm |
In my page controller, I have overridden the InitializeMainBindingSource method, like this:
protected override void InitializeMainBindingSource()
{
base.InitializeMainBindingSource();
WorkItem.Items.Add(MainBindingSource, "SalesOrderBindingSource");
}
Now, when I want to reference the current item, I would use something like this:
EntityBindingSource mBS = WorkItem.Items.Get<EntityBindingSource>("SalesOrderBindingSource");
SalesOrderMaster mSO = (SalesOrderMaster)mBS.Current;
int mIndex = mSO.Custindex;
When I run this code, the EntityBindingSource (mBS) comes back null. Am I not adding the binding source early enough?
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 22-Oct-2007 at 2:42pm |
The code needs to read
WorkItem.RootWorkItem.Items.Add(MainBindingSource, "SalesOrderBindingSource");
The ListConverterService is not aware of the modules work item. Now that it is with the use of the RootWorkItem Items collection, there is still a problem. The ListConverterService is not running MakeMyListConverter but once when the view is created. If I am wanting the ListManager to reference the current customer index, then I need to do something else, somewhere else. The predicate has to exist elsewhere, it seems.
Am I getting derailed?
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 22-Oct-2007 at 2:58pm |
So why doesn't this work:
protected void AddListManager_FilteredList<T>(EntityListConverter<T> pListConverter, EntityColumn pColumn) where T : Entity
{
mColumn = pColumn;
EntityList<T> aList = (EntityList<T>)pListConverter.ListSource.List;
EntityListManager<T> listManager = new EntityListManager<T>
(pListConverter.EntityManager.PersistenceManager,
IsExistingEntity,
null);
aList.ListManager = listManager;
}
private bool IsExistingEntity<T>(T pEntity) where T : Entity
{
// Is the foreign key equal to the presented index
EntityBindingSource mBS = WorkItem.Items.Get<EntityBindingSource>("SalesOrderBindingSource");
SalesOrderMaster mSO = (SalesOrderMaster)mBS.Current;
if (mSO != null) { mIndex = mSO.Custindex; }
if (mIndex == (int)pEntity.GetColumnValue(mColumn.ColumnName)) { return true; };
return false;
}
private int mIndex = 0;
private EntityColumn mColumn;
Shouldn't the ListManager be using the predicate method to detemine the inclusion of a given entity? Perhaps I am misunderstanding the usage of this predicate thing.
|
|
Linguinut
Senior Member
Joined: 14-Jun-2007
Location: United States
Posts: 394
|
Post Options
Quote Reply
Posted: 22-Oct-2007 at 3:21pm |
I walked this dog. Man, is he big! Each entity in the list was run through the predicate. That seems to be working. Now, I need to get the list to "refresh" when the SalesOrderMaster.Custindex changes. What is the slick way of doing that? How is it done with the ListConverter?
By the way, this code will only work with the SalesOrder entity. I should think of a way of getting this to work for other entites, as well, and not limit its implementation.
|
|