Catel nested UserControl: ViewModel instantiated multiple times (with Example) - catel

I have a Problem with Catel, ViewModels are instantiated multiple times.
This is a duplicate of my own question, but the old question is a big wall of text (which didnt help), and now I decided to rather include a demo-Project.
The demo-Project can be downloaded from here:
Demo-Project (VS2013)
Here is the Problem:
Run Project,
Open one Customer (double click or select then "Edit")
Observe: the Nested Controls for the Orders: "OrderViewModelID" is 11...20 (actually you cannot see 16...20, forgot the scrollviewer)
--> it should be "1...10" cause it's the first 10 ViewModel of type Order created.
--> reason: OrderViewModel is instantiated MULTIPLE TIMES per Model
Click on "New Shipper" (any order)
"Cancel" the new Window
Observe: the "OrderViewModelID" is now 21...30 (they were instantiated yet again!!!)
I put lots of time in this Problem already, and I just cannot find the reason.
Any help / insights?
Johannes Colmsee

This was a bug. It has been fixed, see the issue report for the latest information.
btw. I really recommend that you use Catel.Fody, it will result in much cleaner view models.

I have to inform you, that the Bug is only fixed partly.
I will Highlight the steps which still are broken:
Run Project,
Open one Customer (double click or select then "Edit")
Observe: the Nested Controls for the Orders: "OrderViewModelID" is 11...20 (actually you cannot see 16...20, forgot the scrollviewer)
--> it should be "1...10" cause it's the first 10 ViewModel of type Order created.
--> reason: OrderViewModel is instantiated MULTIPLE TIMES per Model
- Click on "New Shipper" (any order)
- "Cancel" the new Window
- Observe: the "OrderViewModelID" is now 21...30 (they were instantiated yet again!!!)
Update:
It was a bug in Catel 4.4 which has been fixed. Link to the Catel Issue Tracker Item

Related

Coded ui objects in UIMap

I have a question regarding coded ui UIMap.
Every time I record an action on the same application, coded ui generates a new object for the same window in the application.
It looks like:
UIAdminWindow
UIAdminWindow1
UIAdminWindow2
and so on...
every window class holds different buttons, even though it's the same window.
Thus it's very hard to keep code maintenance.
What i would like is that every time i perform actions and records on a window, even if not at the same time, the already generated class for this window, will be updated with the new controls.
any suggestions to why it happens?
Thanks a lot!
You can clean up your UIMaps by doing two things:
Use the UIMap Toolbox (from codeplex) to move controls within the UIMap so they are all under one control tree.
When you have duplicate UI controls, go to the properties for the action that references the duplicate control and change the UI Control property to point to the original control in the UIMap.
The duplicate trees should now be unreferenced and you can delete it from your map, keeping things clean.
And yes, it's a pain to do, but it's worth it for maintainability.
In UIMap.uitest you can change the action name and the control name for better maintenance.
For example: you can set UIAdminWindow as FirstAcessWindow or other name that will express comfortably the control or the action.
What I can guess is that there is some randomly generated content or element identification data such as class or title that may be causing it. This may be caused by different username for example. Also you can update the element from UI map element tree.

#SetViewInfo - Issue when clearing filter

I have a problem that have me stumped.
I have been searching for a solution, but haven't found a working one yet. The solutions I seen introduces other issues.
Here is the scenario:
I have a frameset with two frames: 'Navigator' and 'Main'.
In the 'Navigator' frame I display a form called 'Navigator'. It contains an outline, to display a menu.
In the 'Main' frame I display the view selected by the user in the navigator.
So this is a very traditional Notes client application.
I now want to add a checkbox at the top of the view (in the action bar), allowing the user to filter the view by his/her own name. I use #SetViewInfo for this, and it all works perfect.
The issue is when the user switch views. The #SetViewInfo filter stays active when switching to a different view, so after some searching I found some solutions:
In http://www-01.ibm.com/support/docview.wss?uid=swg21204481 IBM suggests to put the following code in the QuerySave event:
#SetViewInfo([SetViewFilter]; temp ; 0 ;1)
When I am switching view or closing the view, I get the error message "Cannot execute the specified command".
In http://www-10.lotus.com/ldd/bpmpblog.nsf/dx/using-setviewinfo-in-a-notes-client-application-to-create-a-user-specific-view Andre Guirard suggests to put the following code in the QuerySave event:
#SetTargetFrame("frameName");
#UpdateFormulaContext;
#Command([OpenView]; #Subset(#ViewTitle; -1));
#SetViewInfo([SetViewFilter]; ""; "columnName"; 1)
I modify this to match my frame name and the programatic name of the first column in my view:
#SetTargetFrame("Main");
#UpdateFormulaContext;
#Command([OpenView]; #Subset(#ViewTitle; -1));
#SetViewInfo([SetViewFilter]; ""; "Adjuster"; 1)
This works perfectly when switching between view. But when I close the application while I am in this particular filtered view, the application is re-opened automatically. This happens no matter if the filter is enabled or not when closing the view.
However, when the view repopens, the frameset is not reloaded, it is just the view with the built-in view navigator to the left.
I finally got this to work by (in the built-in view navigator) selecting another view that the one where I filter data. This fixed the issue for a while, but then it starts again, and the filtered view is active in the navigator.
Obviously it is the OpenView command that is causing this, but if I remove just that line, I get the "Cannot execute the specified command" error again.
Any suggestions/pointers? I am using Notes 8.5.3 running on Windows 7 Professional.
This question can also be found in the IBM developerWorks forum for Notes 8.5:
http://www-10.lotus.com/ldd/nd85forum.nsf/DateAllThreadedWeb/08c73910571306c485257b2b0061ef91
First thing, I would suggest to make sure your view frame is always called "NotesView". You will have much less compatibility issues if you do this.
Secondly, I presume when you say you put it in the QuerySave event you really mean the QueryClose event? Views do not have a QuerySave event.
Thirdly, I find the #UpdateFormulaContext line is not needed. This is what I have in my view QueryClose...
#SetTargetFrame("NotesView");
#Command([OpenView]; #Subset(#ViewTitle; -1));
#SetViewInfo([SetViewFilter]; ""; "<programmaticColumnName>"; 1)
And I can close the app while in the view without any problems.

Creating a new NSManagedObject within an NSPersistentDocument refuses to save even though undo shows as possible

I have a CoreData / NSPersistentDoc app. It works fine.
I added a new entity to the MOM, and updated the version.
Now, when I create new instances of that Entity inside the MOC, the "Save" menu item remains disabled until/unless I create any instances of the old Entities that were already in the app.
The red dot button on titlebar correctly goes black to show that the document has changed - but OS X / NSDocument refuses to acknowledge this - it is impossible to do a Save.
Any ideas?
I found the cause / solution - it was my own bug, but this answer may help others with similar issues.
I was using Apple's official approach for enabling the Copy/Paste menu items (by implementing validateMenuItem), and returning true/false for copy and paste at the right times.
And I was returning NSPersistentDocument's implementation for everything else (which included Save, although I didn't see that).
Then, when I added my new NSManagedObject, I added a sub-view, and sub-view-controller, and I delegated the validateMenuItem to this - i.e. so that it could handle it's own copy/paste status.
...but I had no code path for "if it's not copy paste, and it's not handled by the child, and it's not handled by my NSPersistenDocument subclass ... then hand it to NSPersistentDocument to decide"...
...and so the Save menuitem was never being enabled.

Core data dirty flag not being set

I have a core data document based cocoa app that is working well except for one slightly odd problem.
For some reason, if I make a change to any of my fields the menu/window don't seem to recognize it - ie. the red close button doesn't get the black 'dirty' indicator and the File/Save menu item isn't enabled. However, if I attempt to close the application (via command-Q), I do get the popup asking me if I want to save my changes.
It seems that the document's dirty flag is being set, but the window/menu items aren't reacting to it. I am curious as to where I might look to see why this might be the case. I suspect that it may have something to do with my window not knowing about my ManagedObjectContext...
The only slightly atypical behaviour is that my document's makeWindowControllers method has been overridden and I am adding my window controllers using a call to my document's [self addWindowController:xxx] method. My window controllers subclass from NSWindowController so I had to add my own instance variable to each window controller to hold the ManagedObjectContext, but I suspect that this isn't getting passed to the window/menu. Not sure what the normal pattern is here...
Anyway, any thoughts would be much appreciated. Thanks
From the description it sounds like your UI elements are not actually bound to the document itself. If so, then the UI elements are not observing the document and are not reacting to changes in the document. Check the bindings.
Thanks in part to TechZen, and also re-reading my own question (in particular, where I said "I suspect that it may have something to do with my window not knowing about my ManagedObjectContext") I started to look at the bindings for my WindowController subclass.
As it turned out, I hadn't bound the window outlet for the File's Owner to my actual NSWindow. As soon as I did that, the black dirty dot and the window's menus started behaving correctly.

Magento _prepareLayout() called 5 times to many

** New EDIT **
so what I'm trying to do is this.
I want the to add new form elements generated by my module on the product view of the following url
http://magento.example.com/catalog/product/view/id/46
ultimately these elements will be determined to show up by a related table in my module
I expected that if I extended Mage_Catalog_Block_Product_View in my module as shown below I would be able to create a block in the product form that would contain such form fields, only if he are in the related table in my module
so I created a test.phtml file in
app/design/frontend/default/default/templates/<module>/test.phtml
then as you can see in my the View.php file described bellow I built the block and displayed it in the product view.
It did appear but 5 times too many. from the answers below this is normal so that answers the question as to why the it shows up five times but leaves the question what is the proper way to proceecd since this plan is not going to work
** End New Edit **
in my module I call _prepareLayout() and it does this 5 times when i pull up the page
here's my code
in
/app/code/local/Namespace/Module/Product/Veiw.php
class <Namespace>_<module>_Block_Product_View extends Mage_Catalog_Block_Product_View {
protected function _toHtml() {
return parent::_toHtml();
}
public function _prepareLayout() {
$block = $this->getLayout()->createBlock(
'Mage_Core_Block_Template',
'my_block_name_here',
array('template' => '<module>/test.phtml')
);
if ($block){
$this->getLayout()->getBlock('content')->insert($block)->toHtml();
}else{
echo "no block";
}
return parent::_prepareLayout();
}
}
NOTE:
I just noticed this also takes away the price availability qty and add to cart button. which is also a problem
EDIT
First I want to thank you all for your answers. Second i want to give you more context
the reason for choosing to do this in the module is that I don't want the block to show up on every product . What i have is a table of what I'll call custom options containing properties of the product sort of like hair color height weight etc and depending on what set of properties are attached to the product (if any) will depend on what html content will show up on the page.
so in one case it my get a drop down menu and in another case it may get an input box. the other very important piece is that this must be setup so that I can give the end result out as a module that can be installed and not worrry that it won't show up if someone upgrades there magento
that said does it still make sense to do this all in the xml file ?
It seems to me that your code is overriding a core Magento module in order to achieve what could be easily done in the layout xml configuration. I would strongly recommend the follwing:
Use the built-in configuration mechanisms (e.g. layout xml - read Alan's excellent tutorial here) instead of writing code whenever possible.
Don't override the core code
if you must change the behaviour of the core code, use an Observer rather than Rewrite/Override
if you absolutely must Override, always call parent::whatever()
For example, if you create a <module>.xml layout file in your theme (app/design/frontend/default/<theme>/layout), you could use the following code:
<catalog_product_view>
<reference name="content">
<block type="module/block" name"my_block_name_here" template="module/test.phtml"/>
</reference>
</catalog_product_view>
You would then need to use a getChildHtml('my_block_name_here'); call within your phtml to position the block.
So unless there is other functionality happening inside your _prepareLayout, there's no need to override the core, or even to override the default catalog.xml.
EDIT (small edit above)
So now in your Block (I would recommend that you call it Namespace_Module_Block_Product_Customattributes or something like that), you are not overriding the core Product_View block, but merely processing your logic for what html widgets to use to render your custom attributes. Leave the rest of the tier prices, add to cart, other generic product block code, etc to Magento to work out.
If you are worried about the upgrade path for your module's users, you should definitely NOT be overriding core code. Use the configuration approach and very selectively introduce code that "plays nice" with the system rather than try to boss it around with overrides.
I took a look at a stock Magento install of CE 1.4.1, and unmodified the _prepareLayout method is called six times when loading the URL
http://magento.example.com/catalog/product/view/id/46
That's because the class is instantiated six times. So that's the correct behavior.
As for the vanishing element, I can'y say for sure, but your override to _prepareLayout doesn't appear to either
Do the same things as Mage_Catalog_Block_Product_View::_prepareLayout
Call parent::_prepareLayout();
When you override a class in a Magento you're replacing an existing class with your own. If you change a method, you're responsible for that old code being run.
It's not clear what you're trying to accomplish here. You should consider breaking your problem down into smaller problems, and then posting one (or more) "I tried X, expected Y, and got Z" type questions. As written no one's going to be able to answer your question.

Resources