Prism5 PopupWindowAction and injection - wpf

I looked at part of InteractivityQuickstart official example.
<prism:InteractionRequestTrigger SourceObject="{Binding ItemSelectionRequest, Mode=OneWay}">
<prism:PopupWindowAction>
<prism:PopupWindowAction.WindowContent>
<views:ItemSelectionView />
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
So, ItemSelectionRequest called less-parametre constructor
public ItemSelectionView()
{
this.DataContext = new ItemSelectionViewModel();
InitializeComponent();
}
in code-behind of ItemSelectionView.
Questions:
1) How possible to set DataContext without "new", because
public ItemSelectionView(ItemSelectionViewModel model)
or
[Dependency]
public ItemSelectionViewModel ViewModel
{
set { this.DataContext = value; }
}
doesn`t work.
I need to get some services in ViewModel => i need to call something like this
public ItemSelectionViewModel(IEventAggregator eventAggregator)
{
_eventAggregator=eventAggregator;
}

If you need a service for your Popup ViewModel, you could get it by using the ServiceLocator.
public ItemSelectionView()
{
InitializeComponent();
DataContext = ServiceLocator.Current.GetInstance<ItemSelectionViewModel>();
}

Rather than use the ServiceLocator to set your ViewModel as Brian Lagunas suggests, why not have a parameterless constructor for ViewModel, set the ViewModel directly in your View class (XAML or code-behind), and use the ServiceLocator within the ViewModel itself to get the services (or their interfaces) your ViewModel needs? I suggest this for two reasons:
Using the ServiceLocator in the constructor of the View for the popup will give you an error of "ServiceLocationProvider must be set" at design time within the "prism:PopupWindowAction.WindowContent" section. (Though it works fine at runtime.)
You've already been forced into a situation where you have to bypass dependency injection in some manner, so why not simplify the code, particularly if you only need access to one service anyway.
So you can do something like this:
public ItemSelectionViewModel()
{
_eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
}
And if you only need to use the IEventAggregator object once, there's no reason to even assign it to a field. Just use the ServiceLocator call where you need to get the Event Aggregator and remove your explicit constructor entirely.

Related

WPF Call Method On User Control With Binding

I created a Task List control. I have an AddTask method on it. I'd like to call this method from the host Window.
I found a few posts here in SO and other sites that suggest using an interface, then looping over all the controls in the window to find the control, then getting a reference to it and using that to call the method. Here's an example:
Call method on various user controls
But is it possible to call a method somehow with binding? Assume someone is using MVVM and the Window's VM wants to fire the control's AddTask method. is this possible?
Thanks!
If you really want to do it (in a possible) the right way i'd tell you to write about MVVM.
Binding and methods work very well in MVVM using Commands
Here it is my solution
Create a ViewModel class
Create a nested class MyCommandBehaviour that implements ICommand (some people create the class in a different class)
In the view model create a property MyCommandBehaviour MyCommand
In the constructor of the view model instantiate that property
In The XAML bind the button {Binding MyCommand}
Set the DataContext of the window (or user control) to the view model
Note: I usually create the Command nested class with a constructor that accepts the 'parent' view model. Because the class is nested it can directly access the view model private members
public class OkCommand : System.Windows.Input.ICommand
{
private MyViewModel _vm;
public OkCommand(MyViewModel vm)
{
this._vm = vm;
}
public bool CanExecute(object parameter)
{
return true;//I never use this and the event below
}
#pragma warning disable 0067
public event EventHandler CanExecuteChanged;
#pragma warning restore 0067
public void Execute(object parameter)
{
//do your stuff. Note you can access the MyViewModel members here via _vm
}
}

Is DataBinding to a composite object's fields possible?

I have a WPF window with controls I wish to bind to my model. The model implements INotifyPropertyChanged to notify the view when the Properties change value. The Properties are primitives backed by fields, e.g:
private bool m_isRunning;
public bool IsRunning
{
get { return m_isRunning; }
private set
{
m_isRunning= value;
OnPropertyChanged("IsRunning");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (String.IsNullOrEmpty(propertyName))
{
return;
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
This works fine for primtiive values. I also have a composite object with various primitive properties and a hash table. Or, I'd like to bind to an ObservableCollection's Count property. I would like to bind my View controls to properties within the composite object, but I do not think this is possible. Something like:
<Run Text="{Binding Path=CompositeObject.SomeInnerProperty, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
This doesn't seem possible, but is there some other way? I feel like my only option is to expose properties that map in to the inner property of the composite object, but this seems like a lot of repetiion, e.g.:
public bool SomeInnerProperty
{
get { return m_myComposite.SomeInnerProperty; }
private set
{
m_myComposite.SomeInnerProperty= value;
OnPropertyChanged("SomeInnerProperty");
}
}
There's nothing wrong with binding to something like CompositeObject.SomeInnerProperty, however if CompositeObject does not implement INotifyPropertyChanged, then your UI won't get notified of the change and know that it needs to update when SomeInnerProperty changes.
Also, note that you can only bind to properties (with get and set methods), and not fields. So you can bind to public string SomeValue { get; set; } but you can't bind to public string SomeValue;
In regards dealing with repetitive code, I personally use some Visual Studio macros to write my public properties for me, so perhaps you could look into doing something like that if you don't want to implement INotifyPropertyChanged on your CompositeObject class. It should be noted that Macros were removed from Visual Studio 2012 though, so if you have a newer version you might need to use some other alternative like creating an add-in to run your macros
I had this same problem some time ago. Look at how I solved it:
MVVM INotifyPropertyChanged conflict with base class PropertyChange
Basically I created a Base class that implemented INotifyPropertyChanged and I made all my classes inherit from that base class and data binding worked fine.
You have two options:
If your model classes do not implement INPC, then create wrapper properties in your ViewModel like you suggested, or
Implement INPC in your model and just expose your main object in the ViewModel, you can bind as deep as you want as long as inner properties notify changes.

Stuggling with WPF MVVM Unity, Generic Repository

How can I inject my CustomerRepository into my CustomerVM view model? In my view, a WPF Page I have:
<Page.DataContext>
<viewModel:CustomerVM/>
</Page.DataContext>
But my view model constructor obviously has parameter passed in,
public CustomerVM(ICustomerRepository customerRepository)
{
//this._customerRepository = customerRepository;
}
I get
Type 'CustomerVM' is not usable as an object element because it is not
public or does not define a public parameterless constructor or a type
converter.
Really struggling to heck.
Any help appreciated.
I don't think you can initialize the DataContext within the XAML if you're using dependency injection. Set the DataContext in the code-behind for the view so Unity can resolve the dependencies. Try adding this to YourView.xaml.cs:
public YourView(CustomerVM viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
The above will work if you are resolving your views through Unity. If not, you can also use the ServiceLocator to resolve the view model:
using Microsoft.Practices.ServiceLocation;
public YourView()
{
InitializeComponent();
this.DataContext = ServiceLocator.Current.GetInstance<CustomerVM>();
}
You might also need to add the following somewhere in your registration code to setup the ServiceLocator if you're not using Prism:
ServiceLocator.SetLocatorProvider(new ServiceLocatorProvider(() => new UnityServiceLocator(_unityContainer)));

WPF Dependency Property workaround

There are 3 UserControls under a MainWindow. Each control have it's own Save Button. The Mainwindow has a SaveAll button.
The MainWindow has a ContentControl and the content property is binded to the VM. At runtime on ButtonClickCommand, the View is instantiated and assigned to the Content Property.
This SaveAll button will internally call methods associated with UserControls Save button. As such, SaveAll doesn't have it's own Method.
This has to be implemented by DependencyProperty.
I had once seen this scenario implemented in a Business App, but somehow missed the concept behind it.
I can't get what was the logic behind this, but it's a very useful thing.
Now I have to implement this, but i'm missing a small thing, I dont know.
I hope the scenario is clear.
Please help me in this scenario, with code.
Thanks,
VJ
Since you mentioned MVVM, here's what you might be looking for. Mind you, this will be a lot cleaner and easier if you use an MVVM framework such as Caliburn, but for this sample, its just vanilla MVVM:
public class MainViewModel
{
public MainViewModel()
{
ViewOneModel = new SubViewModel();
ViewTwoModel = new SubViewModel();
Children = new List<SubViewModel>(new[] { ViewOneModel, ViewTwoModel });
}
public void SaveAll()
{
foreach(var child in Children)
{
child.Save();
}
}
public IList<SubViewModel> Children { get; private set; }
public SubViewModel ViewOneModel { get; set; }
public SubViewModel ViewTwoModel { get; set; }
}
public class SubViewModel
{
public void Save()
{
}
}
and on the UI you basically have subviews (UserControls) composed in your main view:
<StackPanel>
<Button Width="100" Height="20" Content="Save All" />
<local:ViewOne DataContext="{Binding ViewOneModel}" />
<local:ViewTwo DataContext="{Binding ViewTwoModel}" />
</StackPanel>
You just need to bind the save methods to your buttons using an ICommand interface (preferably RelayCommand instance).
Imho in this scenario there is no need for RoutedEvents. The way I would solve it:
There is a Main-ViewModel that exposes 3 properties with the Sub-ViewModels.
The MainViewModel is the Datacontext for the window, and the subviewmodels bound to the datacontext of the 3 usercontrols.
The sub vm's are exposing a property with a Save-Command. This command is bound to the save buttons in the usercontrols.
The main vm is exposing a property with a saveall-command, which is bound to the SaveAll button.
In the handler of the save all command you are then iterating over the sub-vm's and call save on them.

Prism MVVM - How to pass an IEventAggregator to my ViewModel

recently I started working with Prism in Silverlight. I want to use the EventAggregator to Subscribe and Publish events between two ViewModels. As I saw on some guides, the ViewModel's ctor should accept IEventAggregator as a parameter. I can't find out how to do this hence my View always wants to initialize the ViewModel with a parameterless ctor.
My ViewModel ctor:
MyViewModel(IEventAggregator eventAggregator)
{
// get the event....
}
My View:
<UserControl ....>
<UserControl.Resources>
<ViewModels:MyViewModel x:Key="MyViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MyViewModel}}">
....
<Grid/>
</UserControl>
I can instantiate the ViewModel in the ctor of the View, and then assign it to its DataContext, but then I must have an IEventAggregator in my View, which I also cannot get. but this is probably not the correct way to pass an IEventAggregator (or any other object! - IUnityContainer for example) to the ViewModel.
Can someone tell me what I'm doing wrong?
You have to resolve your dependency via unity. Have a look at the prism MVVM examples and the ui composition. There the view does not create the view model, but it is exactly the other way round. The view model gets the view injected via constructor injection. The view model sets itself as view model for the view:
public interface IView
{
IViewModel ViewModel{get;set;}
}
public interface IViewModel { }
public View:UserControl, IView
{
public IViewModel ViewModel
{
get{return DataContext as IViewModel;}
set{DataContext = value;}
}
}
public ViewModel:IViewModel
{
public ViewModel(IView view, IEventAggregator eventAggregator)
{
view.ViewModel = this;
//get the event...
}
}
Using this approach you have to register the view model and the view to unity. Afterwards you only have to resolve the view model, the view is injected by the container.
To get the view to the right place on the user interface you have to register the view to a region using the RegionManager. When this is all set up, creating a new view model instance results in adding the view into the registered region so that it shows up on the user interface.
Other than having the ViewModel hook itself into the data context of the view (which I don't like at all), there are two other options that I can think of in Silverlight.
Utilize the ServiceLocator pattern to allow your static resources to create themselves via the container. MVVMLight has a fairly good pattern for this.
Use a framework like Caliburn.Micro, which plugs in a nice set of conventions that will wire up many things based on naming conventions, including bindings and viewmodels.
Maybe you've solved it already but
http://www.emileinarsson.se/silverlight-4-mvvm-prism-unity-dependency-injection/
this post explains how to use Unity in a MVVM environment.

Resources