How instantiate a view model with constructor parameters using Caliburn Micro's IOC? - inversion-of-control

In my bootstrapper file, I want to display the root view for my view model, ONH836ViewModel. This view model derives from BaseViewModel, which has a single constructor with five parameters:
public BaseViewModel(IExportedDataMonitor monitor, IGasLabWorklistService worklistService, IRawDataConduit rawDataConduit,
ISettingService settingService, IDataReportingService dataReportingService)
Here is the pertinent code from the bootstrapper:
class AppInitializer : BootstrapperBase
{
SimpleContainer container = new SimpleContainer();
public AppInitializer()
{
Start();
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
base.OnStartup(sender, e);
DisplayRootViewFor<ONH836ViewModel>();
}
protected override void Configure()
{
container.RegisterSingleton(typeof(IExportedDataMonitor), null, typeof(FakeExportedDataMonitor));
container.RegisterSingleton(typeof(IGasLabWorklistService), null, typeof(FakeGasLabWorklistService));
container.RegisterSingleton(typeof(IRawDataConduit), null, typeof(FakeRawDataConduit));
container.RegisterSingleton(typeof(ISettingService), null, typeof(FakeSettingService));
container.RegisterSingleton(typeof(IDataReportingService), null, typeof(FakeDataReportingService));
container.RegisterSingleton(typeof(BaseViewModel), null, typeof(ONH836ViewModel));
}
The OnStartup method throws a NullReferenceException on the DisplayRootView line. I assume this happens because I am doing something wrong in the Configure method. Can someone identify and correct my mistake?

Start() should be Initialize() for one, assuming v2.xx of CM. save yourself some typing referring to the following code.
container.Singleton<ONH836ViewModel>();
for your interfaces I would suggest
container.Instance<IExportedDataMonitor>(new FakeExportDataMonitor());
and they can be chained...
container.Instance<IGasLabWorkListService>(new FakeGasLabWorklistService())
.Instance<IRawDataConduit>(new FakeRawDataConduit())
.Instance<ISettingService>(new FakeSettingService());
more than likely the reason for NullReference was due to Configure never being called due to Initialize() not being called in the Constructor.

Related

MVVM: OnBindingContextChange: PropertyChanged not firing in new view model

I am coding a Xamarin app and doing my best to adhere to MVVM, which I actually really like
I commonly have ContentPages containing references to Views.
I set the binding context to a VM in the Page, and then make use of OnBindingContextChanged in the view
This allows me to use PropertyChanged method to then respond to display logic conditions for my View
I've used it several times successfully but I am baffled why an additional implementation isn't working
Page looks like this
public partial class BindingTextPage : ContentPage
{
public BindingTextPage()
{
InitializeComponent();
this.BindingContext = new ViewModels.LocationsViewModel();
}
}
View looks like this
private LocationsViewModel_vm;
public BindingTestView()
{
InitializeComponent();
System.Diagnostics.Debug.WriteLine("Debug: Initialised BindingTesView view");
}
protected override void OnBindingContextChanged()
{
System.Diagnostics.Debug.WriteLine("Debug: BindingTest: OnBindingContextChanged: Context " + this.BindingContext.GetType());
_vm = BindingContext as LocationsViewModel;
_vm.PropertyChanged += _vm_PropertyChanged;
}
private void _vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
try
{
System.Diagnostics.Debug.WriteLine("Debug: BindingTest: Method called");
System.Diagnostics.Debug.WriteLine("Debug: BindingTest: Property " + e.PropertyName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Debug: BindingTestView: Error changing context " + ex.Message);
}
}
Extract of view model, very simply in this case setting a string and hence changing a property, which I would have expected would then cause PropertyChange to fire?
public LocationsViewModel()
{
tempMessage = "this is from the view model";
}
public string tempMessage
{
get
{
return _tempMessage;
}
set
{
_tempMessage = value;
OnPropertyChanged(nameof(tempMessage));
}
}
My debug statements when it boots up shows that OnBindingContextChange is being called, but in this one instance _vm_PropertyChanged never fires? I'd expect tempMessage being set to do so?
The order of events in your code is the following
Constructor of LocationsViewModel is called
From your constructor, you are setting tempMessage
The setter of tempMessage calls OnPropertyChanged, since the event is null at the time being, it's not fired
Constructor of LocationsViewModel is left
Page.BindingContext is set
OnBindingContextChanged is called
LocationsViewModel.PropertyChanged is subscribed by your page
Since the event is raised (or it's tried to) before your page subscribes to, your page simply does not get informed about the event being raised. If you set the value after the event has been subscribed to, the handler will be called as expected.
e.g.
protected override void OnBindingContextChanged()
{
_vm = BindingContext as LocationsViewModel;
_vm.PropertyChanged += _vm_PropertyChanged;
_vm.tempMessage = "Hello, world!"; // clichée , I know
}

afterCompose never executes on initialization

I have a controller that extends window and implments IdSpace, AfterCompose.
But the function afterCompose never executes when the controller is initialized. A cant figure out what I am missing. My code for this part:
DataTemplateWindowController.java
public class DataTemplateWindowController extends Window implements IdSpace, AfterCompose {
...
public DataTemplateWindowController() {
Executions.createComponents("dataTemplate.zul", this, null);
Selectors.wireComponents(this, this, false);
Selectors.wireEventListeners(this, this);
}
#Override
public void afterCompose() {
Do something smart!!
}
}
And the initializetion.
HomeWindowController.java
public class HomeWindowController extends SelectorComposer<Component> {
...
#Wire
Window homeWindow;
DataTemplateWindowController fa2;
public void setDataTemplate() {
fa2 = new FA2WindowController();
fa2.setParent(homeWindow);
}
}
The page loads fine, but the afterCompose function never executes.
I know that i can just avoid implementing AfterCompose and then run the function fa2.afterCompose() after initialization but I expect AfterCompose to be able to do the job for me.
As you can see in the javadoc of AfterCompose (of org.zkoss.zk.ui.ext.AfterCompose) interface :
Implemented by a component if it wants to know when ZK loader created
it. If this interface is implemented, {#link #afterCompose} is called,
after ZK loader creates this component, all of its children, and
assigns all properties defined in the ZUML page. It is so-called
"compose".
So the method : "afterCompose" will never be call automatically by your own java code (the code in your method setDataTemplate() in your example). It will only be called if you use your component in a ZUL page.
And you can also see in the Javadoc of org.zkoss.zk.ui.ext.AfterCompose:
If it is created manually, it is caller's job to invoke {#link#afterCompose}.
If you don't need to set any properties or child in you afterCompose process, just don't use this interface and put your code in the constructor, otherwise, you will have to call it manually when you need it (usually in the doAfterCompose of your SelectorComposer) :
public class HomeWindowController extends SelectorComposer<Component> {
...
#Wire
Window homeWindow;
DataTemplateWindowController fa2;
#Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
setDataTemplate();
}
public void setDataTemplate() {
fa2 = new FA2WindowController();
fa2.setParent(homeWindow);
fa2.afterCompose();
}
}

SwipeRefreshLayout error

I am trying to implement swiperefreshlayout and I am getting error at "this"
public class viewBets_activity extends ActionBarActivity {
SwipeRefreshLayout swipeLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewbets);
swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(this);
swipeLayout.setColorScheme(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
}
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
swipeLayout.setRefreshing(false);
}
}, 5000);
}
}
I am getting error at swipeLayout.setOnRefreshListener(this); screenshot below
Well, now that you added the screenshot, the error is clear.
You're passing the wrong argument into setOnRefreshListener()! And of course, this makes sense, if you think about it. Your class is a ActionBarActivity. You're trying to set the OnRefreshListener as an ActionBarActivity...doesn't make any sense! You need to change your code to this:
swipeLayout.setOnRefreshListener(new OnRefreshListener()
{
#Override
public void onRefresh()
{
// what you want to happen onRefresh goes here
}
});
Here, you're creating a new OnRefreshListener object which you're adding as the listener.
For the future, in general, any time you have a setOn______Listener() method, the argument you'll be passing will be a On_____Listener object that you've customized. You can either created separately, or create it right in the set method the way I did in my answer.
Your class is missing
implement SwipeRefreshLayout.OnRefreshListener
This allows the listener to refer to the overridden method onRefresh when passing through this as the argument for setOnRefreshListener

Override TestNG's getTestName method

I execute a TestNG test using a dataProvider.
So I set the testName via #BeforeMethod and I override getTestName().
This works so far, but it seems TestNG is calling the test's getTestName in the beginning
before it starts. This happens when an exception was thrown during configuration, so the #BeforeMethod is not executed and therefore my test name is null.
Is there anyway to call the original method, the one that would have been called if I would not have overwritten it :D since I implement an interface an do not extend from another class I cannot use super.getTestName().
Any way to solve this may be?
#Test(groups = {TestGroups.READY}, description = "check help on each tab")
public class HelpTest extends TestControl implements ITest {
// overriding to return my individual testname, but is null at the beginning
#Override
public String getTestName() {
return TestControl.getCurrentTestName();
}
#DataProvider(name = "tabs")
public Iterator<Object[]> tabs() {
Set<Object[]> list = new LinkedHashSet<Object[]>();
for (Tab tab : Tab.values()) {
list.add(new Object[]{tab});
}
return list.iterator();
}
// before the test below starts, i set my individual testname
#BeforeMethod
public void setTestName(Method method, Object[] testData) {
TestControl.setCurrentTestName(method.getName() + "_" + StringUtils.capitalize(testData[0].toString().toLowerCase()));
}
// executing the test with the given data provider
#Test(dataProvider = "tabs")
public void testHelpSites(Tab tab) throws Exception {
TestActions.goTab(tab).callHelp(tab).checkHelp();
}
}
I guess I figured it out, I also use a TestReporter via AbstractWebDriverEventListener and ITestListener and on its onTestStart(ITestResult result) it's calling the test's name and that's the source of the call before the #BeforeMethod call.
I solved it by checking if result.getName() is null, which calls the test's getTestName() if it implements ITest and if it's null I use the original name from result.getMethod.getMethodName(). Not pretty, but rare :D
I could solve this problem using ITestNGMethod testng class.
ITestNGMethod method = result.getMethod(); // result is ITestResult Object
method.getMethodName(); // This will return method name.
My complete method here:
#Override
public void onTestSuccess(ITestResult result) {
ITestNGMethod method = result.getMethod();
String message = "Test Execution is Successful:"+method.getMethodName();
}
Hope this helps

class member returns null after osgi bind method

My problem is that in the main class I have some osgi references that work just fine when the class is call. But after that all the references became null. When I close the main windows and call shutdown method, the hubService reference returns null. What do I do wrong here?
private void shutdown() {
if(hubService == null) {
throw new NullPointerException();
}
hubService.shutdownHub(); // why is hubService null?
}
// bind hub service
public synchronized void setHubService(IHubService service) {
hubService = service;
try {
hubService.startHub(PORT, authenticationHandler);
} catch (Exception e) {
JOptionPane.showMessageDialog(mainFrame, e.toString(), "Server", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
// remove hub service
public synchronized void unsetHubService(IHubService service) {
hubService.shutdownHub();
hubService = null;
}
If a field can be read and written by multiple threads, you must protect access to read as well as write. Your first method, shutdown, does not protect the read of hubService so that the value of hubService can change between the first read and the second read. You don't show the declaration of the hubService field. You could make it volatile or only read when synchronized (on the same object used to synchronized when writing the field). Then your shutdown implementation could look like:
private volatile IHubService hubService;
private void shutdown() {
IHubService service = hubService; // make a copy of the field in a local variable
if (service != null) // use local var from now on since the field could have changed
service.shutdownHub();
}
I assume your shutdown method is the DS deactivate method? If so, why do you shutdown in the unset method as well in the shutdown method?
Overall the design does not seem very sound. The IHubService is used as a factory and should return some object that is then closed in the deactivate method. You made the IHubService effectively a singleton. Since it must come from another bundle, it should handle its life cycle itself.
Since you also do not use annotations, it is not clear if your set/unset methods are static/dynamic and/or single/multiple. The following code should not have your problems (exammple code with bnd annotations):
#Component public class MyImpl {
IHubService hub;
#Activate
void activate() {
hubService.startHub(PORT, authenticationHandler);
}
#DeActivate
void deactivate() {
hubService.shutdown();
}
#Reference
void setHub(IHubService hub) { this.hub = hub; }
}