Silverlight ChildWindow not disposed using MEF and MVVM - mvvm

I'm not sure if what I'm experiencing is the same as here: Silverlight ChildWindow Memory Leak
but...:
I've got a Silverlight ChildWindow with 3 radio buttons in the same group with IsChecked all set to false in XAML, I don't want any of them selected upon opening. I open up the ChildWindow from my viewmodel:
if (_NewChildWindowCommand == null)
_NewChildWindowCommand = new RelayCommand(param => _cwService.ShowDialog(_newLocation, new NewViewModel(), closed =>
{
if (_newLocation.DialogResult.HasValue && _newLocation.DialogResult.Value)
{
//do something
}
_newLocation = null;
_newLocation = _container.GetExportedValue<INewChildWindow>();
}));
I then select one of the radio buttons hit OK. It Closes, I open it up again and the ChildWindow seems to have been disposed since upon opening, none of those radio buttons are selected (the way it should be). So I select a radio button again,hit OK, It Closes...But the third time I open the ChildWindow, it has the same radio button selected as when I closed it. This is what I don't understand. I thought by setting _newLocation=null like I did and then getting INewChildWindow from the container would give me a new ChildWindow but it doesn't seem to be the case. I tried calling GC.Collect() after setting _newLocation to null but that didn't work, and I tried setting the PartCreationPolicy to NonShared on the ChildWindow, however that doesn't make a difference since the instance of the ChildWindow is being stored in _newLocation and the class containing _newLocation isn't disposed of:
[ImportingConstructor]
public HomeViewModel(IChildWindowService cwService, INewLocationChildWindow newLocationChildWindow)
{
if (!IsDesignTime)
{
_cwService = cwService;
_newLocation = newLocationChildWindow;
_catalog = new AggregateCatalog();
_catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(_catalog);
}
}
Is there something else going on here?

Set the creation policy of the ChildWindow to NonShared. Then replace _container.GetExportedValue<INewChildWindow>() with _container.GetExport<INewChildWindow>(). This will give you a Lazy<INewChildWindow>, and you can use the Value property to get the child window. Then to release the export call _container.ReleaseExport, passing in the Lazy that was returned by the call to GetExport.

Related

$ionicHistory.goBack() not working correctly with ion tabs

My page contains 3 tabs, if i forward to next page from tab3 and then coming back from that page using $ionicHistory.goBack() it redirects to tab1. how to make it redirects to tab3 itself
function sample($scope,$ionicHistory){
$ionicHistory.goBack();
};
}
I'm not sure it's possible to do that just through $state. I'm new to Ionic myself as I had my first peek back in December (2016). However, I happened to have this exact scenario. This is how I solved it.
In my case, I was not using tabs. Instead, I had three different DIVs that were visible depending on the "tab number". When initializing the view, I set it to "1" and used the property to control what code is executed.
I'm guessing that the control you're using has a property like that to identify and set the particular tab you need, as this is the most likely way to change tabs on tab-click. Consider putting the value of that property "tab #" into the appropriate service used by the controller. This is a stripped-down version of actual code in one of my services defined via Factory.
YourService.js:
// controllers are instances. When navigating away, state is lost. This
// tracks the tab we wish to view when we load the home page.
var activeHomePageTab = 1;
var service = {
getActiveTab: getActiveTab,
setActiveTab: setActiveTab,
...
};
return service;
////////////////
function getActiveTab() { return activeHomePageTab; }
function setActiveTab(num) { activeHomePageTab = num; }
...
Here, the functions are private. In your controller, when you set your tab, also set this property. As a singleton, this will remain in effect as long as your application is running.
Next, in your init() routine, when the controller is loaded, check for this property and set the tab if it is defined:
function init() {
var tab = YourService.getActiveTab();
if (tab !== undefined) {
setTab(tab);
} else {
setTab(1)
}
...
}
Of course, there are other ways - maybe using Value or a property on a Constant object.

durandal 2.0 custom dialog master-detail

After upgrading to durandal 2.0, I found I needed to convert my master list page to use the showDialog function instead of showModal.
Previously my master model looked like this:
define(['durandal/amd/require', 'durandal/app', 'durandal/viewLocator', 'durandal/system', 'durandal/plugins/router', 'durandal/lib/tableModel', 'viewmodels/product'], function (require, app, viewLocator, system, router, table, product) {
var tm = {
tableModel: new tableModel(),
createProduct: function (data) {
app.showModal(product, data);
}
}
//...
return tm;
}
Then in my product detail view page I could close the modal easily like so
data-bind="click: $root.modal.close">Close
Now in Durandal 2.0 it is much harder to get right.
The code in the masterpage is now
define(['durandal/app', 'durandal/viewLocator', 'durandal/system', 'plugins/router', 'lib/xhrs', 'lib/tableModel'], function (app, viewLocator, system, router, xhrs, table, product) {
var tm = {
tableModel: new tableModel(),
createProduct: function (data) {
app.showDialog(product, data);
}
}
//...
return tm; }
But the way to access the close function is annoying:
Firstly I have to require the 'plugins/dialog' into the product detail viewmodel; which I would prefer not to do as I don't think the detail viewmodel needs to know that it is a dialog, only the master list viewmodel needs to know that.
then in the compositionComplete event of the product detail view model I assign:
prodedit.close = function () {
dialog.close(prodedit);
}
(prodedit is the returned as the product detail vm)
In this way the product detail dialog can be closed using this:
data-bind="click: $root.close"
OK NOW HERE IS MY ISSUE:
This will work to popup the dialog once or twice, but then fails from then onward without an error. The only thing I can see is that dialogActivator.activateItem hits its fail line: dfd.resolve(false);
Interestingly if I do pause long enough on breakpoints the issue does not occur. But once it occurs once, it never works again to open the dialog.
Is there a better way to do this?
Thankyou.

ExtJS 4: Prevent changing tab using TabBar

I don't use tab panel just tab bar, and have to prevent changing tab by some criteria.
In ExtJS docs I found change event for Ext.tab.Bar, but it fires when tab is already changed. So preventDefault() and return false are not working in this case.
Second I tried is set Ext.tab.Tab.handler property when tabs were initialized, but it fires when tab button is already clicked. So preventDefault() and return false don't work too.
Can ony body help with this? How can I prevent changing tabs using only Ext.tab.Tab and Ext.tab.Bar?
Thx.
I think you can use the 'beforetabchange' event on the tab panel itself.
From sencha docs: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.tab.Panel-event-beforetabchange .
Return false in any listener to cancel the tabchange.
Edit
Maybe you could then extend the Ext.tab.Bar component and register the beforechange event by modifying the setActiveTab method, I think it's a pretty easy modification
setActiveTab: function(tab) {
//test the beforechange return
if (tab.disabled && me.fireEvent('beforechange', tab) === false) {
return;
}
var me = this;
if (me.activeTab) {
me.previousTab = me.activeTab;
me.activeTab.deactivate();
}
tab.activate();
if (me.rendered) {
me.layout.layout();
tab.el && tab.el.scrollIntoView(me.layout.getRenderTarget());
}
me.activeTab = tab;
me.fireEvent('change', me, tab, tab.card);
}
Add a controller action "beforeshow" on the tab panel container and disable the listeners. Allows the tabs to behave normally without clickability.
component.down("#tabPanel").tabBar.clearListeners();

Identify which instance of the view is currently active in RCP?

I am creating an RCP application. I need to open multiple instances of the same view but with different data. I did it by setting secondary id for different instances of the same view. Specifically, my problem is as follows: Please take a look
I have a graph view called Views.GraphView. I opened different instances of it from a command called openGraphView to show different graphs. The command is as follows:
page.showView("Views.GraphView", Integer.toString(instanceNum++), IWorkbenchPage.VIEW_ACTIVATE);
Now, I have a command called TreeLayout on this Views.GraphView toolbar, which suppose to change the layout of the graph and it will operate on each instance of the view. But for this, I think, I need to identify which instance of the view is active. The TreeLayout command looks something like this:
IViewPart findView = HandlerUtil.getActiveWorkbenchWindow(event).getActivePage(). findView( "Views.GraphView"); //I think in the findView I need to give the id of the view [but how can I put the secondary id?]
GraphView view = (GraphView) findView;
view.changeLayout(); //I wrote this method in the graph view to change the layout
//I just tried to print the secondary id, but it did not print anyting
System.out.println("From treelayout command:- " + view.getViewSite().getSecondaryId());
So how can I identify which instance of the view is currently active and to operate on it?
You can use IWorkBenchPage.findViewReference(String viewId, String viewId) , if it returns null, the view with viewId and viewId is not present in the current perspective.
If you have a ViewReference you can use ViewReference.getView(boolean restore) to get the view
so in your handler you get something like:
final IWorkbenchPage page = HandlerUtil.getActiveWorkbenchWindow(
event).getActivePage();
final int instanceNum = 8;//the number of instances that are created
for (int index = 0; index < instanceNum; index++) {
final IViewReference viewReference = page.findViewReference(
"Views.GraphView", Integer.toString(index));
if (viewReference != null) {
final IViewPart view = viewReference.getView(true);
if (view instanceof GraphView) {
final GraphView graphView = (GraphView) view;
graphView.changeLayout();
}
}
}
The view.getViewSite().getSecondaryId() method is the good one to identify a secondary view. This method only returns the Null string for the "primary" view: the one opened when user click Window -> Show View - Your View.
I don't understand why your view toolbar button has to operate on all the view instances. TO my eyes, you should have one button in each view instance toolbar operating only in its own view. If you really need to operate from one button to ALL the views I think you will have to keep the open views references yourself, because I think the workbench doesn't provide a findViews method returning a view array.
using the below code you should be able to get the current active view.
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart()
Active view and Editor name display on MessageDialogbox
public class Active_Workbench extends AbstractHandler{
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
// A part service tracks the creation and activation of parts within a workbench page.
IPartService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService();
MessageDialog.openInformation(HandlerUtil.getActiveWorkbenchWindow(
event).getShell(), "Current Workbench Window", service.getActivePart().getTitle().toString());
return null;
}
}
I hope this answer is useful.

Whats the best way to programatically open a pane inside Dijit AccordionContainer

I am trying open & close accordion panes programatically. Here is the simplified version of my code. Even though I set the first pane's selected to false and and second pane's selected to true, only the first pane opens when it loads on the browser (FF3).
var accordionContainer = new dijit.layout.AccordionContainer().placeAt("test");
var accordPane = new dijit.layout.ContentPane({"title": "test", "content":"hello"});
var accordPane2 = new dijit.layout.ContentPane({"title": "test1", "content":"hello1"});
accordionContainer.addChild(accordPane);
accordionContainer.addChild(accordPane2, 1);
accordPane.startup();
accordPane2.startup();
//accordionContainer.selectChild(accordPane2);
accordionContainer.startup();
accordPane.selected = false;
accordPane2.selected = true;
You can do it like this:
accordionContainer.selectChild( accordPane2 );
Assuming you are using dojo 1.3.
dijit.layout.AccordionContainer is a subclass of dijit.layout.StackContainer, which has selectChild defined.
I set up a demo page where you can see this code in action
If you were calling selectChild before startup, that could cause the error you were seeing since the widget wasn't in a 'complete' state. (Sorry, missed the commneted out code before I posted original answer)