Revision history [back]

click to hide/show revision 1
initial version

asked 2012-12-20 11:54:46 +0800

cyiannoulis gravatar image cyiannoulis

How to detach / reattach MVVM windows?

I really need help with the following scenario. We are migrating an application from MVC to MVVM and i think we are stuck. Any help would be much appreciated. Sample source code at the end of this message.

  1. The main-view.zul contains a workspace Div.
  2. The main-view creates the 'search-view.zul' with parent the workspace div.
  3. The search-view sends the global command 'openDetailView' to the main-view.
  4. The main-view detaches the search-view window and creates the 'detail-view.zul' with parent the workspace div.
  5. The detail-view sends the global command 'reattachSearchView' to the main-view.
  6. The main-view detaches the detail-view window and re-sets the search-view with parent the workspace div.

At this point the search-view.zul stops responding and sends all commands to the main-view generating the following message: "cannot find any method that is annotated for the command close with @Command in MainViewVM"

I understand that the whole thing has to do with the lifecycle of each viewmodel's binder but i cannot find anything useful in the documentation. The same functionality could be achieved easily using SelectorComposers and the old data binder. The only alternative i have found is to make the windows visible/invisible instead of detach/setParent but this is not what we want.

<?page title="Main View" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winMainView" title="Main View" border="normal" height="100%" width="100%" 
        apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.MainViewVM')" >

    <borderlayout>
        <north height="48px" border="none">
            <vlayout>
                <label value="This is the Main View" />
            </vlayout>
        </north>

        <center border="none">
            <div id="divWorkspace" vflex="true" />
        </center>
    </borderlayout>
</window>
</zk>





package test;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Div;
import org.zkoss.zul.Window;

public class MainViewVM {

    @Wire 
    private Div divWorkspace;

    /*
     * The window representing the 'search' sub-view 
     */
    private Window wSearchView;

    /*
     * The window representing the 'detail' sub-view 
     */
    private Window wDetailView;

    @AfterCompose
    public void init(@ContextParam(ContextType.VIEW) Component view)
    {
        Selectors.wireComponents(view, this, false);

        /*
         * create the search-view
         */
        wSearchView = (Window) Executions.createComponents("/test/search-view.zul", divWorkspace, null);
    }

    @GlobalCommand
    public void openDetailView() {
        wSearchView.detach();
        wDetailView = (Window) Executions.createComponents("/test/detail-view.zul", divWorkspace, null);
    }

    @GlobalCommand
    public void reattachSearchView() {
        wDetailView.detach();
        wSearchView.setParent( divWorkspace );
    }
}





<?page title="Search" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winSearch" title="Search" border="normal"
        apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.SearchViewVM')" >

    <vlayout>
        <label value="This is the 'search' view embedded inside the main div" />
        <button label="Close 'search' view and open the 'detail' view" onClick="@command('close')" />
    </vlayout>
</window>
</zk>





package test;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.Command;

public class SearchViewVM {

    @Command
    public void close() {
        BindUtils.postGlobalCommand(null, null, "openDetailView", null);
    }

}





<?page title="Detail" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winDetail" title="Search" border="normal"
        apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.DetailViewVM')" >

    <vlayout>
        <label value="This is the 'detail' view embedded inside the main div" />
        <button label="Close 'detail' view and try to re-attach the 'search view" onClick="@command('close')" />
    </vlayout>
</window>
</zk>





package test;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.Command;

public class DetailViewVM {

    @Command
    public void close() {
        BindUtils.postGlobalCommand(null, null, "reattachSearchView", null);
    }

}

thanks to all /costas

How to detach / reattach MVVM windows?

I really need help with the following scenario. We are migrating an application from MVC to MVVM and i think we are stuck. Any help would be much appreciated. Sample source code at the end of this message.

  1. The main-view.zul contains a workspace Div.
  2. The main-view creates the 'search-view.zul' with parent the workspace div.
  3. The search-view sends the global command 'openDetailView' to the main-view.
  4. The main-view detaches the search-view window and creates the 'detail-view.zul' with parent the workspace div.
  5. The detail-view sends the global command 'reattachSearchView' to the main-view.
  6. The main-view detaches the detail-view window and re-sets the search-view with parent the workspace div.

At this point the search-view.zul stops responding and sends all commands to the main-view generating the following message: "cannot find any method that is annotated for the command close with @Command in MainViewVM"

I understand that the whole thing has to do with the lifecycle of each viewmodel's binder but i cannot find anything useful in the documentation. The same functionality could be achieved easily using SelectorComposers and the old data binder. The only alternative i have found is to make the windows visible/invisible instead of detach/setParent but this is not what we want.

<?page title="Main View" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winMainView" title="Main View" border="normal" height="100%" width="100%" 
        apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.MainViewVM')" >

    <borderlayout>
        <north height="48px" border="none">
            <vlayout>
                <label value="This is the Main View" />
            </vlayout>
        </north>

        <center border="none">
            <div id="divWorkspace" vflex="true" />
        </center>
    </borderlayout>
</window>
</zk>





package test;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.GlobalCommand;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Div;
import org.zkoss.zul.Window;

public class MainViewVM {

    @Wire 
    private Div divWorkspace;

    /*
     * The window representing the 'search' sub-view 
     */
    private Window wSearchView;

    /*
     * The window representing the 'detail' sub-view 
     */
    private Window wDetailView;

    @AfterCompose
    public void init(@ContextParam(ContextType.VIEW) Component view)
    {
        Selectors.wireComponents(view, this, false);

        /*
         * create the search-view
         */
        wSearchView = (Window) Executions.createComponents("/test/search-view.zul", divWorkspace, null);
    }

    @GlobalCommand
    public void openDetailView() {
        wSearchView.detach();
        wDetailView = (Window) Executions.createComponents("/test/detail-view.zul", divWorkspace, null);
    }

    @GlobalCommand
    public void reattachSearchView() {
        wDetailView.detach();
        wSearchView.setParent( divWorkspace );
    }
}





<?page title="Search" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winSearch" title="Search" border="normal"
        apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.SearchViewVM')" >

    <vlayout>
        <label value="This is the 'search' view embedded inside the main div" />
        <button label="Close 'search' view and open the 'detail' view" onClick="@command('close')" />
    </vlayout>
</window>
</zk>





package test;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.Command;

public class SearchViewVM {

    @Command
    public void close() {
        BindUtils.postGlobalCommand(null, null, "openDetailView", null);
    }

}





<?page title="Detail" contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winDetail" title="Search" border="normal"
        apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.DetailViewVM')" >

    <vlayout>
        <label value="This is the 'detail' view embedded inside the main div" />
        <button label="Close 'detail' view and try to re-attach the 'search view" onClick="@command('close')" />
    </vlayout>
</window>
</zk>





package test;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.Command;

public class DetailViewVM {

    @Command
    public void close() {
        BindUtils.postGlobalCommand(null, null, "reattachSearchView", null);
    }

}

thanks to all /costas

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More