I am developing a Windows Phone 7 app and am using the MVVM pattern. I have a need to pass a parameter to the contructor of the ViewModel for a page. All my datacontexts and binding are done in XAML. Through my research I've seen that I need to do so using a dependency injector such as NInject.
Here's a little detail on whats going on:
I have a page with a ListPicker that lists various tasks. Each task has a unique TaskID. When an item is selected I need to open another page that will show the selected Tasks detail. My ViewModel and binding is all done and works if I use a static TaskID in the ViewModel but of course I need to use a variable.
I've setup NInject in the project and the various classes needed such as ViewModelLocator and my NInjectModule as shown here:
public class LighthouseNInjectModule : NinjectModule
{
public override void Load()
{
this.Bind<TaskViewModel>().ToSelf().WithConstructorArgument("TaskID", 2690);
}
}
Note that I have hardcoded a TaskID here and using this code this value properly gets injected into my constructor. Of course, this is hardcoded and I need to get the TaskID for the selected ListPicker item. I know how to get the selected ID from the ListPicker but how do I make NInject aware of it so when my class constructor is run it will have the correct value?
Here is the basic definition of my ViewModel class showing use of the Injector attribute.
public class TaskViewModel : INotifyPropertyChanged
{
[Inject]
public TaskViewModel(int TaskID)
{
//run function to get data using TaskID
}
}
WithConstructorArgument has another oveload that accepts a lazy evaluated Func<Context, object>.
Related
I am having issue with the code, I have my page layout as below.
I am communicating to database to get data for Main Content. It is List<SomeClass> that I am getting from database. Now I want same List<SomeClass> to be available for RightContent. Both components are custom and have different layout but can share same List rather than making same call twice. (Sequence is MainContent Initialized() method gets called first)
I created a service class AppDataService with below property. Also added to IServiceCollection services in startup.
public List<SomeClass> sharedListOfSomeClass = new List<SomeClass>();
In MainContent I am injecting AppDataService and assigning sharedListOfSomeClass with database values.
Now if I am injecting AppDataService in Right Content and and trying to access sharedListOfSomeClass I am getting it as null.
I know I am missing binding here because both the components are different in terms of html and can't bind it to any html tags.
Could any one please help me out to achieve this. I want to make single call to database for both the components.
If you want to have some global state of the app and share it between different components, the most reasonable way to do it is to create a State class that will contain the global state data
public class State
{
public List<SomeClass> SomeClassObjectsCollection { get; set; } = new List<SomeClass>();
}
In your Startup (or Program if you use Blazor wasm) you should add a State object as a singleton
services.AddSingleton<State>()
and on every page, where you need an access to state (or even in _Imports if you want to access it often) add
#inject State State
After that on any page you can refer to State.SomeClassObjectsCollection and get the same data.
The key point is adding a state as a singleton. If you will add is as transient or even scoped, the dependency container will create new instances of State.
One option is to pass the list to the components as parameter. Define a parameter in the component's code.
[Parameter] public List<SomeClass> sharedListOfSomeClass { get; set; }
In the parent pass the set the parameter:
<MyCustomComponent sharedListOfSomeClass="#MyVariableHoldingTheListValues" />
Other way I can think of is to make a static list and reference the static list in the components.
The scenario of the injection gives you null because the service could be registered as transient or scoped servervice. Not as singleton.
Does anyone have a clue on how to control IsPresented property from a child view model?
I'm implementing a custom NavBar where I want to simulate the Hamburger icon behavior so my child page on load has
NavigationPage.SetHasNavigationBar(this, false);
which hides the navigation par.
Inside Xaml file I have a button which I want to bind to a PropertyCommand of child viewmodel and show Master page, basically somehow to call Master's IsPresented.
Thanks.
There are a couple of ways to go about it.
The way I would do it would be to use MVVM and use an interface to access the 'presenting the Master page' functionality where its needed.
public interface ICustomMasterDetail
{
void SetMasterPresented(bool isPresented);
}
Now extend on the MasterDetailPage and also implement the above interface
public class CustomMasterDetail : MasterDetailPage, IRootMasterDetail
{
public CustomMasterDetail() : base()
{
//constructor code
}
public void SetMasterPresented(bool isPresented)
{
IsPresented = isPresented;
}
}
Using using an IoC container to register and resolve the interface will let you use its functionality from where ever you want.
The other solution would be to just use a static variable to store the instance of your MasterDetailPage and access that directly to change the IsPresented property
In Autofac we have PropertiesAutoWired. Its written there
If the component is a reflection component, use the PropertiesAutowired() modifier to inject properties.
Appears that we should use this when we need to do property injection. So I want to know what would it be in case of Ninject.
Ninject doesn't feature an equivalent to Autofacs PropertiesAutowired(). Instead one marks properties with an attribute [Inject] - the binding of the component is unaffected:
public class FooBar
{
// will be injected
[Inject]
public IDependency Dependency { get; set; }
// will not be injected
public IFalaffel Falaffel {get; set;
}
The binding is not affected. For example
Bind<FooBar>().ToSelf();
is perfectly valid and (attributed) properties will be injected.
Also see the Property Injection documentation on the ninject wiki.
Furthermore note, that constructor injection is the preferred alternative. You should only use property injection in case you can't use constructor injection or some other special circumstances, like you cannot get rid of an inheritance hierarchy and don't want to pass constructor parameters down 10 steps in a class hierarchy...
Alternative to using Attributes
If you don't want to clutter your code with references to Ninject, you can also do property injection like this:
Bind<FooBar>().ToSelf()
.OnActivation((ctx, instance) => instance.Dependency = ctx.Kernel.Get<IDependency>());
(or "Using LocationInterceptionAspect and IInstanceScopedAspect together")
Using Postsharp I'm trying to inject a property into a target class using 'IntroduceMember' and then using the 'OnGetValue' functionality of LocationInterceptionAspect dynamically give it a value on inspection.
Originally I thought that I'd need two separate aspects, one for the field injection and one for the location interception but managed to combine the two by implementing the IInstanceScopedAspect interface and inheriting from LocationInterceptionAspect.
The problem is that if I set a breakpoint I will see the property that's been injected, but if I set another breakpoint in the OnGetValue method (that gets fired for each property on the class) I can't see it...
Here's some sample code:
[Serializable]
class DALDecoratorWrapper : LocationInterceptionAspect, IInstanceScopedAspect
{
public override void OnGetValue(LocationInterceptionArgs args)
{
if (args.LocationName == "Type")
{
args.Value = "computed value here";
}
args.ProceedGetValue();
}
[IntroduceMember(OverrideAction = MemberOverrideAction.OverrideOrFail)]
public String Type { get; set; }
I was also hoping there was a better way of doing this than overriding OnGetValue as that's called for each getter where really I want to only target the getter of the property that's been injected
Cheers
I'm studying MEF and I'm not able to resolve a problem.
I have a main application, called MainMEF, and a simple module, called SimpleModule. This one consists of a single UserControl which is loaded dynamically.
When MainMEF starts up, I would be able to pass to the module a reference to main application contained into MainMEF.
How could I fix this?
Lots of questions regarding this already.
You could pass it after initialisation using a property:
How do I populate a MEF plugin with data that is not hard coded into the assembly?
Or use MEF constructor parameters:
MEF Constructor Parameters with Multiple Constructors
The export looks something like this:
[Export(typeof(ITest))]
class Test : ITest
{
void Test()
{ }
[ImportingConstructor] //<- This is the key bit here
void Test(object parameter)
{ }
}
Then when composing your catalog do this:
catalog.ComposeExportedValue( /* parameter here */);
catalog.ComposeParts(this);