I have a rootcontroller pushed on a UINavigationController.
Inside that rootcontroller class, I can access the UINavigationController with this.NavigationController
However, this rootcontroller has a ScrollView and I'm adding subcontrollers (or more precise, the View of this subcontroller) to this ScrollView.
I would now like to access the UINavigationController from inside such subcontroller.
Following properties are all null
this.NavigationController
this.ParentViewController
this.PresentedViewController
this.PresentingViewController
It seems in ObjectiveC you can use following code
YourAppDelegate *del = (YourAppDelegate *)[UIApplication sharedApplication].delegate;
[del.navigationController pushViewController:nextViewController animated:YES];
Unfortunately, i don't know how to map this to C# in MonoTouch.
I tried the following, but it's not working:
UIApplication.SharedApplication.KeyWindow.RootViewController.NavigationController
I know I could pass the UINavigationController object to all my classes (parameter in constructor), but that's probably not the cleanest way to go.
To extend poupou's answer, here is an example of what I usually do in my AppDelegate class:
Add a static property of the AppDelegate itself:
public static AppDelegate Self { get; private set; }
Add my root navigation controller as a property:
public UINavigationController MainNavController { get; private set; }
In FinishedLaunching:
Self = this;
window = new UIWindow(UIScreen.MainScreen.Bounds);
this.MainNavController = new UINavigationController(); // pass the nav controller's root controller in the constructor
window.RootViewController = this.MainNavController;
// ..
This way, I can access the root view controller from anywhere, like this:
AppDelegate.Self.MainNavController.PushViewController(someViewController);
... instead of having to write this all the time:
AppDelegate myAppDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
myAppDelegate.MainNavController.PushViewController(someViewController);
Plus, I can directly access all other AppDelegate's properties I might have.
Hope this helps.
UIApplicationDelegate does not, itself, define a navigationController property.
OTOH [UIApplication sharedApplication].delegate returns the instance of your own, application specific, UIApplicationDelegate - so it's a great place to share stuff (and why it's frequently used).
What commonly happens, in ObjectiveC, is that this custom ,UIApplicationDelegate-derived, type will implement it's own application-wise properties. IOW YourAppDelegate will implement a navigationController property that can be accessed, anywhere inside the app, by using [UIApplication sharedApplication].delegate.
You can do something very similar in .NET / C#. Simply add your own properties to your AppDelegate type, like this example. You'll be able to access them like Objective-C (if you like) or more directly (e.g. by making them public static properties).
Note that you still have to track and set your properties correctly (just like it needs to be done in Objective-C too).
Related
I'm trying to connect multiple Viewmodels to a single View using caliburn micro. I found some solution but all seem quite heavy for something that seems to me a quite standard way of doing things.
The reason for being that is the following :
I'm implementing some views and their default ViewModels in an assembly. lets call the assembly HMI.Base with two classes
HMI.Base.ViewModels.BaseViewModel
HMI.Base.Views.BaseViewModel.
I'm then using this view from another assembly. lets call the assembly HMI.ConcreteApp
Usage is quite straightforward and overriding SelectAssemblies() does the trick so the view can be easily located.
Issues are rising when a ViewModel needs to get its data from a specific source. The solution that come to my mind is to extend my ViewModel and Add an element in its constructor being the source of my data and then do the necessary to link those data to the base viewmodel Properties.
So I create a class
HMI.Concrete.ViewModels.CustomViewModel
The implementation looks like this:
using HMI.Base.ViewModels;
public class CustomViewModel : BaseViewModel
{
public CustomViewModel (IConfiguration config, ILoggerFactory loggerFactory, IEventAggregator eventAggregator, DataSourceXYZ data) : base(config, loggerFactory, eventAggregator)
{
Logger.LogInformation("Constructing custom viewmodel that will display as HMI.Base.Views.BaseViewModel");
}
However the name has now changed, so the view cannot be located automatically. Is there a way to simply and clearly say "Use the base class view if no specific view exist with the same name" in the CustomViewModel ?
Without having to do some more fiddling in the bootstrapper, which seems bad to me (except if it isn't ) because all needed extra information are there (we know the base viewmodel why not use the base view to display the data)
I will provide already an answer for the best solution I found even if I would like better:
The solution is at this page
In short :
A custom attribute can be created to indicate the baseViewModel.
The Viewlocator can be changed in the Bootstraper to take it into consideration
And an extra step not in this article to avoid writing it in every application:
create A CustomBaseBoostrapper to write it only once and use it instead of BootstrapperBase.
It is not too bad, but I'm mainly wondering if there is not better and without changing the viewlocator.
I am making a gallery tool that lets you browse and edit objects. I have a 'Library' class that manages the fetching and displaying of the gallery list. I also have an 'ActiveItem' asset that loads all the information of the selected object and deals with modifying it.
Now, there's some information that is stored in the 'library' class (for example the filepath) that I want to use in my activeitem.
I'm a bit confused as to how I can set this up efficiently.
I thought about embedding the activeitem class in the library class, but it gets a bit annoying to have to access all functions and properties of the activeitem through the library class (so instead of writing activeitem.Load() I would have to write lib.activeitem.Load() ). Activeitem already goes 4 levels deep and it's getting a bit much.
Are there other ways of setting this up? Can I store a reference of the library class instance inside the activeitem class, so that the activeitem class can fetch a property of the library instance?
Edit: added some code snippets
This are the class definitions:
class Library
{
...
public string LibDirectory;
...
}
class ActiveAsset
{
...
public SaveAsset()
{
//this method needs to know the LibDirectory property of the libraryclass
}
}
On initiating my winform, I initiate both classes:
Library lib = new Library();
ActiveAsset activeAsset = new ActiveAsset();
Given the concerns in the question comments, if you want ActiveAsset to be able to read information from Library you could change ActiveAsset's constructor to take in Library and store it internally as a private var.
class ActiveAsset
{
private Library _lib
public ActiveAsset(Library lib) {
this._lib = lib
}
public SaveAsset()
{
// reach lib instance from here
this._lib.LibDirectory
//this method needs to know the LibDirectory property of the libraryclass
}
}
If you are worried about design and coupling you could make in interface for Library and then make the constructor use that instead of the Library class
interface ILibrary {
string LibDir { get; set; }
}
class Library : ILibrary {
}
class ActiveAsset
{
private ILibrary _lib
public ActiveAsset(Library lib) {
this._lib = lib
}
public SaveAsset()
{
// reach lib instance from here
this._lib.LibDirectory
//this method needs to know the LibDirectory property of the libraryclass
}
}
As for performance and creating deep levels of nested classes I don't think you will have to worry so much about it, chances are you will hit data save/retrieve performance issues before anything like too many classes. That kind of performance design is only really important when you try to make you code work on small platforms where memory is limited like rasberryPi and such.
I would suggest creating a wrapper class which holds both the Library and the ActiveItem instances. Thus you can have more generalised methods like:
GetAllItems() - gets all items from the library
ActivateItem(Item item) - activates the item provided (stores the given item to a variable in the wrapper class)
etc. Think of that wrapper class as the manager of your application. You would only like to work with that manager regardless of what's beneath it.
first question so I'm open to advice on effectively participating in the StackOverflow community as well as pertaining to the question.
I'm working on a text-based UI in C#. I have an abstract window class and an abstract control class, each of which implements common functionality for the types that inherit them (e.g. pop-up windows or text box controls). Currently, within a program that might implement the library, a developer would have to create window objects and control objects, and then add the controls to their respective windows, and the windows to a window manager class, like this:
var mainWindow = new MainWindow(...);
var textBox1 = new TextBox(...);
mainWindow.AddControl(textBox1);
WindowManager.Add(mainWindow);
This works, but it's a bit clunky. Since a control should never have to exist outside of a window, I was hoping to implement the control types as nested types. However, to maintain extensibility of the program, I'd like for there to be a way to extend the window class with new control types. My question is this: Should I use reflection, or rely on developers using container classes to extend the window class? Alternatively, is there a better way to structure the program than how it's currently laid out?
I've also considered using generics, e.g.:
public abstract class Window : DrawableObject, IWindow
{
public void AddControl <T>(object[] constructorArgs) where T : class, IControl
{
}
}
I'm aiming for ease of implementation without sacrificing extensibility/loose coupling. Thanks in advance for any thoughts!
EDIT: Should clarify, the primary reason for this is to fix some weirdness with how Windows and Controls cooperate. Each control has a parentWindow property which is used to access the window on which a control resides, for various purposes like creating an exit button for a particular window, etc.
Right now, this property is passed to the constructor, but that seems redundant to me since after doing so you have to add the control to the window's control list. I'd like to find a way to set this property when the control is added to a window instead, but restrict this action to when the control is added only, to prevent potential problems if the parentWindow property is changed outside of this context.
The way you coded AddControl method:
public void AddControl <T>(object[] constructorArgs)
where T : class, IControl
{
}
You intend developers to just provide type and your AddControl method will create an instance of it using constructorArgs. This method itself implicitly forces you to use reflection. Anything else does not stand a chance. Because To Add control of type T, Creating Instance of Control of type T is necessary. Since your Window class does not have a clue about T reflection is the only solution.
To facilitate other approaches, you might want to consider few overloads of AddControl.
public virtual T AddControl <T>()
where T : class, new(),IControl
{
//now you can create instance no reflection required
var control = new T();
this.Controls.Add(control);
return control;
}
public void AddControl <T>(T control)
where T : class, IControl
{
}
public abstract void AddControl <T>(object[] constructorArgs)
where T : class, IControl;
Creating an abstract method passes onus of implementation on child class and creating new instance of T can be handled the assuming type of T is known there or at-least all cases of known types of what T might be are handled.
It's a wide scope topic and I guess subjective as well. The best use of OOP is to achieve a design which fits your logical objective whatever that maybe.
I have defined some custom helpers in my MVC3 Razor application (ASP.NET) and in the ViewStart code I would like to access my custom helpers.
I noticed that they are not accessible in _ViewStart which then seems understandable as ViewStart derives from ViewStartPage and not WebViewPage.
So I tried to define the helper in a custom ViewStart class but as it turns out I then need access to a ViewDataContainer to be able to initialize the helper.
So, the question is, how can I access my custom helper from ViewStart (or a custom ViewStartPage) and if not, can I then initialize the viewDataContainer constructor property with NULL. I don't expect needing any ViewData access in my custom ViewStartPage.
I also tried implementing the custom ViewStart class but it gives me this error:
CustomViewStart does not implement inherited abstract member 'System.Web.WebPages.WebPageExecutingBase.Execute()'
what should I do in that execute method? I don't want to do anything fancy in the customViewStart, just access my helper.
OK, it is after all possible as I suspected, just needed some nitty gritty technical details sorted out first.
public abstract class CustomViewStartPage : System.Web.Mvc.ViewStartPage {
public Helpers.InvariantHelper ConfigHelper { get; private set; }
public CustomViewStartPage() : base() {
ConfigHelper = new Helpers.InvariantHelper();
}
}
Now, I have defined several custom helpers in my WebViewPage custom base page and they do their work for views. However, in the ViewStart I needed to do certain stuff (here is only a trivial example) that did not require accessing the ViewContext (as I originally thought).
So, with this I can now have this in my _ViewStart.cshtml:
#* Views/_ViewStart.cshtml *#
#inherits MyNamespace.Web.Mvc.CustomViewStartPage
#{
var something = ConfigHelper.DisableParentLayout;
}
Sure, one can also use static members of a class as #MortenMertner indicated (a fresh view at the problem from outside) but in some cases that may not be what you truly want. This example here is senseless but serves as purpose to indicate how it could be accomplished for those who need.
If on the other hand a ViewContext needs to be accessed (another valid scenario) you may want to look at the post in my comment above which describes how to modify this custom view start page to access the context without errors.
From what I understand, the _ViewStart file is not a regular view. It can only be used to set defaults, such as the layout view, for other views.
For instance, this is the complete contents of my _ViewStart file:
#{ Layout = "~/Views/Shared/Layouts/Wide.cshtml"; }
If this holds true there would be no need for custom helpers in the file, and you're likely trying to solve a problem that you shouldn't have in the first place.
As an aside, you can add assemblies and namespaces in Web.config to avoid having to import them in specific views. I use this to import my models, enums and extension methods.
I have a UserControl I've created which imports several parts using the [Import] attribute.
public class MyUserControl : UserControl, IPartImportsSatisfiedNotification
{
[Import]
public IService Service { get; set; }
public MyUserControl()
{
}
public void OnImportsSatisfied()
{
// Do something with Service.
}
}
This UserControl is instantiated from XAML, so its imports aren't being satisfied and OnImportsSatisfied isn't being called.
<local:MyUserControl />
My question is how can I satisfy my class's imports when it's being created in XAML.
From MSDN:
To be instantiated as an object element in XAML, a custom class must
meet the following requirements:
The custom class must be public and must expose a default (parameterless) public constructor. (See following section for notes
regarding structures.)
The custom class must not be a nested class. The extra "dot" in the full-name path makes the class-namespace division ambiguous, and
interferes with other XAML features such as attached properties.
If an object can be instantiated as an object element, the created object
can fill the property element form of any properties that take the
object as their underlying type.
You can still provide object values
for types that do not meet these criteria, if you enable a value
converter. For more information, see Type Converters and Markup
Extensions for XAML.
From there, you have two choices:
1) Using a TypeConverter:
Using a type converter will allow you to instantiate an object without a parameterless constructor, but you will have to provide a TypeConverter that will do the instantiation.
Now, I never had to use it, I cannot help you further with that.
2) Retrieve IService using the ServiceLocator:
public class MyUserControl : UserControl
{
public IService Service { get; set; }
public MyUserControl()
{
Service = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IService>();
// You can do something with Service here already.
}
}
I realize it is a change in the design of your class, but hopefully you can cope with it.
Hope this helps,
Bab.
if you did not want mef to create your usercontrol, you have to use the compositioncontainer in your usercontrol and call GetExport direct. but then you have the problem to get the instance of your compositioncontainer :)
ps: i let mef create my wpf views in my applications.
(I'm resurrecting this in case anyone comes across it. As a disclaimer, I'm no expert and these are just solutions I found to be working.)
I found that calling CompositionContainer.ComposeParts(myUserControl) works. I call this on the control's constructor. You'll need to get a reference to the CompositionContainer somehow:
public MyUserControl()
{
compositionContainer.ComposeParts(this);
}
Additional solution:
This is probably unnecessary, but here's another way. This is far more convoluted but it does allow you to "Import" your usercontrol in XAML.
To have your imports satisfied, MyUserControl needs to be exported and then instantiated by MEF. My solution was to have static field in a class that holds a "Locator" object. This Locator object is responsible for importing and returning exported objects. Then I could refer to this static field in XAML, like so:
<ContentControl Content="{Binding MyUserControl, Source={x:Static v:SomeClass.Locator}}">
SomeClass has a static property called Locator which gets assigned early in the application's life cycle. The Locator could then have a MyUserControl property that gets Imported.
(Disclaimer: the links below are to my own framework and the solution, being as crude as it is, if used should be used with care.)
To provide an example of the above, I'll explain how I implemented it in my framework:
In my case, SomeClass is a subclass of System.Windows.Application that replaces App.xaml, and ViewLocator is assigned on its OnStartup, as can be seen here.
The ViewLocator class is a System.Dynamic.DynamicObject that imports views, which have a custom ViewExport attribute. Views are identified using the ViewExportAttribute.Alias property.
This is an example of a view being exported and being assigned an alias.
Finally, the MEF instantiated instance of the view can be used in XAML as follows:
<ContentControl Content="{Binding HomeView, Source={x:Static v:FrameworkApp.ViewLocator}}">