I've been battling with this over the last day, can't seem to get it to work correctly. I would share code but I feel it might confuse matters.
I've created a few ComponentDialogs that are needed to be included in other ComponentDialogs including the main bot.js.
ComponentDialogA is being imported into the main bot.js which gets called fine when I do a replaceDialog or beginDialog. But when I try can call ComponentDialogB from ComponentDialogA it just returns to the last point of ComponentDialogA and fails to hit ComponentDialogB.
So my sub questions are as follows:
Do I need a custom state accessor for each ComponentDialog in order
to do what I want to achieve or is that just for storing specific
data related to that dialog as opposed to the actual dialog position
Related to the first do I need a new dialogSet per ComponentDialog to
handle child ComponentDialogs, to use this.dialogs.add instead of
this.addDialog?
Am I just being dimwitted and messed up my code
somewhere?
I'll try and simplify my code and share later.
Many thanks,
First, there is currently a limitation in v4.2.x version of the libraries that prevent ComponentDialogs from accessing dialogs outside of itself in any way. This means that the dialogs inside of a ComponentDialog can only ever begin dialogs that are siblings to them within that ComponentDialog and never access the outside world.
In 4.3.x timeframe it will be possible for a ComponentDialog to begin a dialog "up" its ancestry chain as well. This means that, for your scenario, if both ComponentDialogA and ComponentDialogB were registered in the same parent DialogSet, ComponentDialogA would be able to call beginDialog('ComponentDialogB' ...) and it would find it.
To be clear though, you will still not be able to address individual dialogs within ComponentDialogs from the outside. Meaning, if your ComponentDialogB had a SubDialogX inside of it, something outside, such as ComponentDialogA, cannot start that "inner" dialog explicitly. Make sense?
Related
I am creating a winRt app. In which I am having a Home.xaml page which having a another page called Market.xaml. So for snapped mode the same code is repeated.
Now my itemListView (used for snapped) and itemGridView (for full view) both have this page (Market)
<views:Market x:Name="viewMarket"/>
And the constructor of this page is called twice which I not want.
So do I use some flag kind of thing or some better approach is there.
Thanks
So, let's talk about this:
XAML is basically a varying syntax to C#. So, when XAML references a control like your views:Market with <Views:Market />, you are actually putting in something like new Views.Market() in both places. Basically, invoking the class twice. Should the constructor not fire twice, the time-space continuum would split in half. Dogs and cats living together, the whole 9 yards.
But, more fundamental here, what is the purpose of the constructor in C#, or in a XAML class? Is to do expensive things that you would not want to repeat? No. The reason for this is because the completion of the constructor is necessary before the UI thread is released and allowed to render the control. The resulting effect is a UI hang.
Moreover, the C# constructor is a synchronous method. It cannot properly invoke or hold asynchronous operations. This means long-running or expensive tasks that should be invoked immediately, should not be invoked in the constructor because it would also require them to be synchronous and UI-blocking. It is because of these last two points I suspect your constructor is being misused.
The solution is in the XAML framework. The XAML Page pipeline includes the constructor (since it is a C# class and they all have it) but it also includes a Loaded event. In many cases, the hard work necessary to fill page controls is in the Loaded handler. This allows the page to render properly, then starts the long-running action that will ultimately and asynchronously update control content.
In WinRT, the Page pipeline also includes an OnNavigatedTo() virtual method in the base that you can override to the same effect. In the override you can include the hard work of talking to a service, deserializing from a file, or whatever you need to make your UI work. Both the Loaded event and the override can be asynchronous, and neither prevent rendering by freezing the constructor.
But, there's another thing to consider since we're in C# and that the rather common pattern called singleton that allows for us to reference a type in two different contexts but without creating a brand new class. This is accomplished by making the class constructor private, but exposing a public property usually called Instance that returns a single, shared instances in some static place.
That might solve your problem already. Then again, none of that is probably what you need. Assuming you already know all that, the quick answer is you can't prevent a constructor because a constructor is necessary to create a new instantiation of any class, including a XAML view. Instead, whatever you are trying to prevent being double might need to be a combination of the discussions above. An offloaded method, and a static reference to prevent duplicate efforts.
Something like this:
public class Market : UserControl
{
public Market()
{
Loaded += Market_Loaded;
}
static bool AlreadyLoaded = false;
void Market_Loaded(object sender, RoutedEventArgs e)
{
if (AlreadyLoaded)
return;
AlreadyLoaded = true;
// TODO: your work
}
}
But that might not do it for you because the static variable is scoped too large. Instead, you can control if it does the big operation with a dependency property you add to your control. With a boolean dependency property set to false, the second control knows not to do something. With it set to true, the first knows to go ahead. And, so on. This prevents all future use of the view or user control in your app from thinking it should not run because of the static property in the above solution. Then again, that might be perfect.
Best of luck!
I have implemented a TabBarController much like the Conference tutorial for iOS. Everything is working well now except it appears that the Init methods on Viewmodels for the tabs never get called as it normally would.
Is there something I forgot to do to ensure that Init is called? If I must, I could move this code to the constructor of the ViewModel, but I'd like to avoid this if possible.
EDIT
I guess what I'm really asking here is if I manually instantiate a viewmodel and "create" a view from it via the extension/helper methods, will init get called at some point in the process? If so, at what point can I expect init to get called on the viewmodel?
The Construction-Initialize-ReloadState-Start (C-I-R-S) sequence is called on an MvxViewModel if it is created using the default ViewModel locator - which is what happens when you call ShowViewModel.
If the ViewModels for the sub-tabs are created by calling new on a ViewModel directly - like in the Conference HomeViewModel.cs#L11 - then obviously this same sequence doesn't happen.
Really the difference here is between:
the tab ViewModels which are just INotifyPropertyChanged objects
the page-level MvxViewModels which are also INotifyPropertyChanged objects, but which you further expect to be initialized within navigations.
If you wanted to unify the two concepts then you probably could... but actually I suspect it might be simpler and cleaner to perhaps give the two class types different names, to just put the init code in the constuctor for the tab view models, or perhaps to just call Init on them yourself in the Home constructor.
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.
I've currently got two view controllers A and B, A uses a segue to push B and this works back and forth nicely, however based on some button presses in view controller B i want to change the text within a UITextView in controller A.
I've had a look at previous posts but i'm a novice at present and was confused by the way in which i should go about doing this.
I'd love to be able to get my head around how interactions are best done between various parts of the app. Also i was wondering if there is a way i can tap into a segue returning to trigger some other code.
Thanks
Edit:
OK perhaps i was a little bit limited with my information, from what i can gather reading other posts they are manually creating a variable for the viewcontroller (A) in viewcontroller (B) then accessing it in the second view controller (B) and setting a variable (property and synthesize) to edit that way, however i have the viewcontrollers embedded in a navigation controller and using a push setup in the storyboard (GUI system). I'm not sure if i have to create a variable to do this or if because they exist in the storyboard there is another way, if someone could just point me in the direction of a post that helps to explain this (i am looking at the moment too) i'd be very grateful.
OK well here's how i got it to work but i imagine there are:
A: Better ways to do it.
B: Changes depending on your setup.
I had my two view controllers embedded in a navigation controller, and used a segue push to access the second view controller each had a different class (all setup in the storyboard thing).
To get it working for me i did the following:
I have a singleton (a class that stores all my data but is global to the app so the variables can be accessed from anywhere in the app) this allows me to have variables that i can access from any view controller. A great tutorial on this can be found here
I then created an NSString variable (passedNote) and updated the value of this variable from the ViewController B, when my button was pressed.
Next when viewController A is loaded (in the viewWillAppear: (BOOL)animated method) i append or replace the value of the textview (dependent on some logic) I have with the global variable (passedNote).
Hope this helps anyone who had the problem.
** 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.