Prism/mef ViewModel: pro and con of property against ctor - mvvm

In the StockTraderRI sample code the ViewModel is injected by MEF using a property:
[Export(typeof(IOrdersView))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class OrdersView : UserControl, IOrdersView
{
public OrdersView()
{
InitializeComponent();
}
[Import]
[SuppressMessage("Microsoft.Design", "CA1044:PropertiesShouldNotBeWriteOnly", Justification = "Needs to be a property to be composed by MEF")]
public IOrdersViewModel ViewModel
{
set { this.DataContext = value; }
}
}
What I wonder is: why not use an ImportingConstructor like this to inject the ViewModel:
[Export(typeof(IOrdersView))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class OrdersView : UserControl, IOrdersView
{
[ImportingConstructor]
public OrdersView(IOrdersViewModel ViewModel)
{
InitializeComponent();
this.DataContext = ViewModel;
}
}
Is there a special feature, problem or reason I miss why the StockTraderRI sample does use a Property instead of a paramter to the ctor?

Because types partially defined in XAML don't play well with parametrized constructors. XAML is built on the "create a blank object and fill in the properties afterwards" paradigm.

Related

Maintain User Control State in UWP Application using Template 10

I am creating UWP app using Template 10. I have created user control like this.
<my:DeviceInfoUserControl OnEndpointTypeChange="{Binding OnEndpointTypeChangeCommand}" Component="{Binding DeviceManagementViewModel,Mode=TwoWay}"></my:DeviceInfoUserControl>
I have Radio Buttons on User Control. I have added User Control on Multiple screens.
This user control has its own ViewModel as well as Some Dependency Properties as follows:
public class DeviceManagementViewModel : ViewModelBase
{
}
public sealed partial class DeviceInfoUserControl : UserControl
{
public bool IsToggled = true;
public DeviceInfoUserControl()
{
this.InitializeComponent();
}
public static readonly DependencyProperty OnEndpointTypeChangeProperty =
DependencyProperty.Register(
"OnEndpointTypeChange",
typeof(ICommand),
typeof(DeviceInfoUserControl), new PropertyMetadata(null));
public ICommand OnEndpointTypeChange
{
get { return (ICommand)GetValue(OnEndpointTypeChangeProperty); }
set { SetValue(OnEndpointTypeChangeProperty, value); }
}
public static readonly DependencyProperty ComponentProperty = DependencyProperty.Register("Component", typeof(DeviceManagementViewModel), typeof(DeviceInfoUserControl), new PropertyMetadata(null));
public DeviceManagementViewModel Component
{
get { return (DeviceManagementViewModel)GetValue(ComponentProperty); }
set { SetValue(ComponentProperty, value); }
}
}
I want to preserve Radio Button Selection across all screens. How should I achieve this?
You have to ensure that the same ViewModel instance is used for all control instance. The XAML way is always create new instance:
<Page.DataContext>
<vm:DetailPageViewModel x:Name="ViewModel" />
</Page.DataContext>
In the Template10's Bootstrapper class with the ResolveForPage method override, you can inject ViewModel's after the page navigation through a custom logic, or through dependency injection LINK
Don't know its better way or not but I have achieved this by making Singletone Viewmodel.
public class DeviceManagementViewModel : ViewModelBase
{
public static readonly DeviceManagementViewModel _instance = new DeviceManagementViewModel ();
private DeviceManagementViewModel ()
{
}
/*Properties and Methods */
}
In Parent Screen ViewModel I have created following property
private DeviceManagementViewModel _deviceManagementViewModel;
public DeviceManagementViewModel DeviceManagementViewModel1
{
get { return _deviceManagementViewModel; }
set { Set(ref _deviceManagementViewModel, value); }
}
I have Instantiated property in Constructor:
public ConfigurationViewModel()
{
DeviceManagementViewModel1 = DeviceManagementViewModel._instance;
}
And on User Control:
<my:DeviceInfoUserControl OnEndpointTypeChange="{Binding OnEndpointTypeChangeCommand}" Component="{Binding DeviceManagementViewModel1,Mode=TwoWay}"></my:DeviceInfoUserControl>

Dependency property inside viewmodel in Prism

Is there any way to declare dependency property inside viewmodel? I want to declare a dependency property inside viewmodel and change it's value through command.
public class MyViewModel : Prism.Windows.Mvvm.ViewModelBase
{
public bool IsPaneVisible
{
get { return (bool)GetValue(IsPaneVisibleProperty); }
set { SetValue(IsPaneVisibleProperty, value); }
}
public static readonly DependencyProperty IsPaneVisibleProperty =
DependencyProperty.Register("IsPaneVisible", typeof(bool), typeof(MyViewModel), new PropertyMetadata(0));
public ICommand VisibilityChangeCommand { get; set; }
public MyViewModel()
{
VisibilityChangeCommand = new DelegateCommand(OnVisibilityChange);
}
private void OnVisibilityChange()
{
IsPaneVisible = !IsPaneVisible;
}
}
Problem is, I am getting some compilation error in IsPaneVisible' getter/setter : "GetValue does not exist in the current context". Is there any alternative way to do this?
A DependencyProperty is used on a DependencyObject, an example of this is a UserControl. Prism's ViewModelBase is no DependencyObject, mainly because this type is platform specific. To support binding from a viewmodel, we typically use INotifyPropertyChanged.
Prism implements this interface in the BindableBase base class, from which ViewModelBase derives as well. You define your properties like this:
private string _imagePath;
public string ImagePath
{
get { return _imagePath; }
set { SetProperty(ref _imagePath, value); }
}
If you install the Prism Template Pack Visual Studio extension, you can use the propp code snippet.

In MVVM Pattern INotifyPropertyChanged can use only in ViewModel or we can use in Model or Bothes?

I read lots of articles, And found that lots of people use INotifyPropertyChanged in ViewModel either Model as well. So, I am confused about INotifyPropertyChanged where to use.
A popular approach is to use a base class which Implements InotifyPropertyChanged interface and then inherit this base class in your View Model.
example:
public class NotifyPropertyBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then inherit the base class in the view model:
class MainViewModel : NotifyPropertyBase
Finally, raise the OnPropertyChanged event in the property setter of your view model passing in the property name string as the parameter:
private string _name;
public string Name
{
get { return _name; }
set
{
_name= value;
OnPropertyChanged("Name");
}
}
Now your UI should update at run time provided the binding is declared correctly in the Xaml.

Does ICommand always requires an object as a parameter?

When I implement the ICommand interface, the following methods are created
#region ICommand Members
public bool CanExecute(object parameter)
{
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
}
#endregion
The interesting part is
public void Execute(object parameter)
{
}
Simply because it indicates that it expects 1 parameter. What if I don't need to pass a parameter? In my ViewModel I have the following code
public class DownloadViewModel : BaseViewModel
{
public ICommand BrowseForFile { get; set; }
public string File { get; set; }
public DownloadViewModel()
{
BrowseForFile = new RelayCommand(new Action<object>(OpenDialog));
}
private void OpenDialog(object o)
{
var dialog = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
File = dialog.SelectedPath;
}
}
The OpenDialog method does not require the parameter but it appears as if I have to just so I can satisfy the Interface.
Am I doing this right or have I missed the point?
Yes, ICommand always needs an object and RelayCommand too. If you don't need it, you pass null and don't use it in your method, which is ugly.
I would use Prism's DelegateCommand instead. This exists in a non-generic version, which doesn't take parameters:
Command = new DelegateCommand(DoSomething);
CommandWithParameter = new DelegateCommand<int>(DoSOmethingWithInt);
Its in the PRISM assembly, which you have to download and reference.
using Microsoft.Practices.Prism;
PRISM
Alternatively, use the MVVMLight toolkit, which provides a command class which does basically the same thing. There is no point in using MVVM without a MVVM framework anyway. I can recommend PRISM, also for it's basic stuff like the DelegateCommand or the EventAggregator.
The fact that Execute takes a parameter is irrelevant to the method from your ViewModel. The only thing that affects what parameters OpenDialog needs is your implementation of ICommand.
If your implementation is, for example:
public class MyRandomCommand : ICommand
{
private readonly Action _action;
public MyRandomCommand(Action action)
{
_action = action;
}
public void Execute(object parameter)
{
_action();
}
...
}
Then no parameters will be required for your OpenDialog method, as you can create a command as follows:
public ICommand Command { get { return new MyRandomCommand(OpenDialog); } }
You can, however, require any signature you like for the method you are passing to your command.
The most common, off-the-shelf implementations of RelayCommand can take methods with either 0 or 1 parameter and will be called from Execute appropriately.

Parameterless implementation for Ninject mappings

i am creating custom membership provider using ninject for binding to sql classes.
my class in looks like
public MyMembershipProvider(IUsersRepository userRepository)
{
this.userRepository = userRepository;
}
How can i create from this parameterless constructor?
kernel.Bind<IUsersRepository>().To<UsersRepository>();
kernel.Bind<MembershipProvider>().To<MyMembershipProvider>();
and then:
public class AccountController : Controller
{
private readonly MembershipProvider _membershipProvider;
public AccountController(MembershipProvider membershipProvider)
{
_membershipProvider = membershipProvider;
}
public ActionResult Foo()
{
// TODO: Use the membership provider to do some processing
return View();
}
}