I am trying to create a user control using MVVM.
Basically I am trying to wrap a combobox that will pull data from a respository. This will allow me to use the same combobox in many different views in my application. There will be many of the wrapped comboboxes throughout the application.
I was easily able to create this control using a DependencyProperty and code-behind. I am now trying to convert this to MVVM and am having trouble figuring out how to get the value back to /from the ViewModel that in bound to the View where my combobox is located.
Any ideas or suggestions would be greatly appreciated at this point.
Thanks,
Eric
It is perfectly acceptable to use a UserControl that has code behind in it when using MVVM. If you really want to move the functionality out of the UserControl, then move it to whichever parent view models will require it. If you don't want to have the same code repeated in several places, you could encapsulate it in a class and add an instance of that class as a property to each of the relevant view models.
if you have a viewmodel that will pull data from a respository - you can use the same viewmodel in many different viewmodels in your application :)
and if you use a datatemplate your views know how to render this viewmodel
<DataTemplate DataType="{x:Type local:MyPullDataViewmodel}">
<view:MyCoolPullDataShowComboboxUserControl />
</DataTemplate>
It's pretty easy.
Let's say you have:
MyUserControlView.xaml
MYUserControlViewModel.cs
MyMainWindowView.xaml - For your MainWindow view (the one containing the UserControl)
MyMainWindowViewModel.cs - Your MainWindow ViewModel.
And you want to bind List<string> MyListToBind
And leave the code-behind completely empty.
MyUserControlViewModel.cs
public class MyUserControlViewModel
{
private List<string> _MyListToBind;
public List<string> MyListToBind { get; set;}
}
MyMainWindowViewModel.cs
public class MyUserControlViewModel
{
private MyUserControlViewModel _MyControlViewModel;
public MyUserControlViewModel MyControlViewModel { get; set;}
}
MyMainWindowView.xaml
<Window ...
xmlns:my="clr-namespace:NamespaceContainingYourUserControlView>
<my:MyUserControlView DataContext = "{Binding Path= MyControlViewModel}"/>
</Window>
MyUserControlView.xaml
<UserControl ...>
<DataGrid ItemsSource = "{Binding Path= MyListToBind}" .../>
...
</DataGrid>
</UserControl>
This doesn't support ViewModel updating View. To do that You have to use either DependencyProperties as you did instead of normal variables (as i did) or use INotifyPropertyChanged(google it, you'll get tons of examples) and OnPropertyChanged event.
You might read up on DataTemplates they are really useful in data binding.
You can find this usefeul:
http://www.youtube.com/watch?v=BClf7GZR0DQ
I sure as hell did !
Good luck.
Related
First of all, I'm newbie in WPF and specially in MVVM. I have a window with diferent tabs and a very large ViewModel with the business logic of the content of every tab. I know it is not right, so now I'm trying to do it more elegant:
As I see googling, an idea is to do a collection of a "base" viewmodel from wich inherit the sub-viewmodels of every tab, and a collection on this "base" viewmodel in the viewmodel of the window.
TabBaseViewModel
Tab1ViewModel inherits TabBaseViewModel
Tab2ViewModel inherits TabBaseViewModel
MainWindow ViewModel --> Collection of TabBaseViewModel
The contents the tabs do not have anything in common along each other.
How I have to proceed?
You should consider using an MVVM framework if you're using MVVM. With Caliburn.Micro for example, you can define your main view as:
<TabControl x:Name="Items">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
Where the data context is a Conductor type that has a collection. The Items property will expose a collection of your view models:
public class MainViewModel : Conductor<IScreen>.Collection.OneActive
{
private OneOfMyViewModels oneOfMyViewModels;
private AnotherViewModel anotherViewModel;
protected override void OnInitialise()
{
// Better to use constructor injection here
this.oneOfMyViewModels = new OneOfMyViewModels();
this.anotherViewModel = new AnotherViewModel();
this.Items.Add(this.oneOfMyViewModels);
this.Items.Add(this.anotherViewModel);
}
protected override void OnActivate()
{
base.OnActivate();
this.ActivateItem(this.oneOfMyViewModels);
}
}
public class OneOfMyViewModels : Screen
{
public OneOfMyViewModels()
{
this.DisplayName = "My First Screen";
}
}
I posted an answer to a different question which shows how to do exactly this: How to Get a Reference to a ViewModel
It's a very simple example, but hopefully should get you started along the right track.
I'm new to WPF and I'm writing a simple test app to familiarize myself with it. My test app will detect all joysticks I have attached to my computer and display information about it. So far, I have this ViewModel:
public class JoystickViewModel
{
public ObservableCollection<Joystick> Joysticks { get; set; }
public JoystickViewModel()
{
GetAttachedJoysticks();
}
private void GetAttachedJoysticks()
{
// populate Joysticks collection by using SlimDX
}
}
And this is my codebehind for my MainWindow.xaml:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new JoystickViewModel();
}
}
And my XAML for MainWindow:
<Window ...>
<Grid>
<ComboBox ItemsSource="{Binding Joysticks}"
DisplayMemberPath="Information.ProductName"/>
</Grid>
</Window>
I followed a tutorial that also populated the ViewModel in its constructor.
My question is, how should I populate the ViewModel? It seems sort of weird to me that I'm population the collection in the ViewModel constructor. Should this logic be in MainWindow's codebehind instead? Or somewhere else altogether? The end goal is to not only have this collection populated, but also updated periodically to reflect the current state (user plugged in new joystick, unplugged existing one, etc...).
The MainWindow code behind is definitively not the place where "business" logic should occur, as the View should be kept as simple as possible.
Keep your fetch/update logic inside of your viewmodel, this way you can test it easily and independently.
From a learning perspective, it's important to keep concerns separated :
the View is bound to the ViewModel, and has no intelligence
the ViewModel has knowledge on how to get the Model
the Model represents the data
In your case, the VM knowledge is at the moment a call inside it's constructor. Later you can change this to call some IJoystickDataService interface, and wire everything using a MVVM framework.
I would have your JoySticks observable collection property (and the code that populates it) in a Model class. The viewmodel simply exposes this same property to the view for binding. The vm should be as thin as possible - ideally just exposing properties that are in the model for binding and not doing any kind of 'business' logic (i.e. populating joystick info as in your case).
This is what I'm trying to do:
I'm writing a UserControl that I want to be consumed by other developers.
I want end users to be able to use my control using Dependency Properties.
<lib:ControlView ControlsText={Binding Path=UsersOwnViewModelText} />
I'm using the MVVM pattern.
I'm binding my ViewModels to their View's using <DataTemplates>
<DataTemplate DataType="{x:Type local:ControlViewModel}">
<local:ControlView />
</DataTemplate>
So I have two questions:
Am I right in thinking that if a UserControl is being consumed in XAML then the UserControl must set the ViewModel as its DataContext when the control's Loaded event fires instead of using the <DataTemplate> method?
How do I allow users to data bind to my control's dependency properties while still being data bound to my ViewModel?
You should separate the two use cases:
The (user) control that will be consumed by other developers.
The user control that will be consumed by your application.
Importantly, the latter depends on the former - not vice versa.
Use case 1 would use dependency properties, template bindings, all the things that go into making a regular WPF control:
MyControl.cs:
public class MyControl : Control
{
// dependency properties and other logic
}
Generic.xaml:
<ControlTemplate Type="local:MyControl">
<!-- define the default look in here, using template bindings to bind to your d-props -->
</ControlTemplate>
You would then define use case 2 as:
MyViewModel.cs:
public class MyViewModel : ViewModel
{
// properties and business logic
}
MyView.xaml:
<UserControl ...>
<local:MyControl SomeProperty="{Binding SomePropertyOnViewModel}" .../>
</UserControl>
Best of both worlds with a clean separation. Other developers depend only on the control, which could (and probably should) be in a completely different assembly than your view model and view.
First off, I don't think MVVM is a good choice if you are developing a UserControl that will be consumed by others. A lookless control is what you really should be developing. Jeremiah Morrill has a blog post about this subject.
With that said, you can set the datacontext with XAML if you have a default public constructor.
Inside ControlView.xaml put:
<UserControl.DataContext>
<local:ControlViewModel />
</UserControl.DataContext>
Basically, instead of binding your UserControl's datacontext to the userControlViewModel, it's better to do it on the first child element of the user control. That way, all the references that you make within the control will be bound to the userControlViewModel, but the dependencies properties can be set from the data context set where you want to use your UserControl.
This is from a project I'm working at:
<UserControl x:Class="Six_Barca_Main_Interface.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Six_Barca_Main_Interface"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="900" d:DesignWidth="900">
<DockPanel x:Name="rootDock" >
<TextBlock>{Binding SomethingInMyUserControlViewModel}</TabControl>
</DockPanel>
</UserControl>
Then on the code behind:
public partial class MyUserControl : UserControl
{
UserControlViewModel _vm;
public MyUserControl()
{
InitializeComponent();
//internal viewModel set to the first child of MyUserControl
rootDock.DataContext = new UserControlViewModel();
_vm = (UserControlViewModel)rootDock.DataContext;
//sets control to be able to use the viewmodel elements
}
#region Dependency properties
public string textSetFromApplication
{
get{return (string)GetValue(textSetFromApplicationProperty);}
set{SetValue(textSetFromApplicationProperty, value);}
}
public static readonly DependencyProperty textSetFromApplicationProperty = DependencyProperty.Register("textSetFromApplication", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, OnDependencyPropertyChanged));
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyUserControl)d)._vm.SomethingInMyUserControlViewModel =
e.NewValue as string;
}
#endregion
Then when you use this on your main view, you can set the dependency property with the value you want to pass to MyUSerControl
A UserControl is part of the "View" in "MVVM" just like the TextBox or ListView controls are part of the View.
Whether you decide to use MVVM to develop your UserControl itself or write it in QBASIC (not recommended) it does not break the MVVM pattern for the consumers of your UserControl so long as they can do every thing they need with your UserControl by binding to DependencyProperty's exposed on your UserControl. i.e. Your UserControl should expose the properties it is dependent upon (hence the name). Once you grasp this DependencyProperty's suddenly make a whole lot of sense and you want their helpful on changed event handlers and default values you specify in their constructor.
If your UserControl is in a different assembly or not I cannot see how that makes a difference.
That said many would advocate you build your UserControl using the MVVM pattern itself for all the good reasons MVVM brings e.g. helping another developer looking at your code. However some things simply are not possible and/or much harder more complex and less performant hacking the XAML to do this - I am not talking about your garden variety Add User Form but for example a UserControl handling the layout of thousands of visuals. Furthermore since you are working in your View you do NOT want your UserControl's ViewModels mixed in with you applications!
Basically I am saying it is well within MVVM not to use MVVM on your View!
I was wondering if in WPF you are able to get the actual instances of the datatemplate objects. For example in the following situation:
<UserControl>
<UserControl.Resources>
<DataTemplate x:Key="MyTemplate">
<CustomControl ></CustomControl>
</DataTemplate>
</UserControl.Resources>
<ListBox DataTemplate="{StaticResource MyTemplate}"></ListBox>
</UserControl>
Assume that CustomControl has a CustomEvent and a public CustomMethod. I want to access that event and the public method in the user control. Is this possible? How would I be able to do this? Thanks in advance for any help.
Cheers,
Nilu
You need to find the ContentPresenter holding the ListBox (by navigating the VisualTree) and then use
myDataTemplate.FindName("myCustomControl", myListBox);
There is an example on MSDN: http://msdn.microsoft.com/en-us/library/bb613579.aspx.
I don't see the ItemsSource databinding on the ListBox, so I'm assuming you left it out. If you bind to something like an ObservableCollection<> then each item in the ListBox will have it's own ViewModel class. You may have public methods on those as much as you like.
If you want an event in the custom control to be handled, handle it in code-behind in the lowest level you can, in this case in the code-behind of the UserControl.
Then, in each ViewModel have an ICommand instance (or a routed command if that suits your purpose). In the UserControl you have a DataContext which you can cast to the type of your ViewModel. So the event handler can access the ViewModel and execute Commands.
Here is Josh Smith's article on Routed Commands which you might find interesting
In this article on Apps with MVVM architecture, Josh described custom ICommands
(This is pseudo-code)
class ViewModelType {
public void DoSomething() { /* ... */ }
public ICommand DoSomethingCommand { get; set; }
public string Property { get; set; }
}
class CodeBehind {
public void EventHandler(object, args) {
(DataContext as ViewModelType).DoSomethingElseCommand.Execute();
}
}
You can create an object which attaches to the CustomControl and interacts with it.
This blogpost here illustrated some useful concepts that we can expand upon: ICommand for Silverlight with Attached Behaviors
So instead of attaching to the click event of a button (which in WPF already has a command anyways) you can create a class which attaches to your custom control.
Following the pattern in the referenced blog post you would end up with:
<CustomControl
MyNamespace:CustomControlCommand.EventCommand=
"{Binding Path=CommandHandler}" />
This would give you access to the events of the CustomControl by turning them into commands.
I'm building a simple UserControl example with DependencyProperties so that the properties of the control can be changed in XAML (code below).
But of course in my application I don't want this control to have tightly-coupled code-behind, but instead the user control will be a view called "DataTypeWholeNumberView" and it will have its own ViewModel called "DataTypeWholeNumberViewModel".
So I am going to implement the DependencyProperty logic below into the ViewModel, but in ViewModels I usually inherit INotifyPropertyChanged which seems to give me the same functionality.
So what is the relationship between:
binding the DataContext of UserControl XAML to its code behind which has a DependencyProperties
binding the DataContext of UserControl XAML (View) to its ViewModel (which inherits from INotifyPropertyChanged) and has properties which implements INotifyPropertyChanged functionality?
XAML:
<UserControl x:Class="TestDependencyProperty827.SmartForm.DataTypeWholeNumber"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Label}"/>
</StackPanel>
</StackPanel>
</UserControl>
Code Behind:
using System.Windows;
using System.Windows.Controls;
namespace TestDependencyProperty827.SmartForm
{
public partial class DataTypeWholeNumber : UserControl
{
public DataTypeWholeNumber()
{
InitializeComponent();
DataContext = this;
}
public string Label
{
get
{
return (string)GetValue(LabelProperty);
}
set
{
SetValue(LabelProperty, value);
}
}
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register("Label", typeof(string), typeof(DataTypeWholeNumber),
new FrameworkPropertyMetadata());
}
}
INotifyPropertyChanged is an interface that exists in .Net since 2.0. It basically allows objects to notify when a property has changed. An interested party can perform certain actions when this event is raised. The problem with it is that it only publishes the name of the property. So you end up using reflection or some iffy if statements to figure out what to do in the handler.
DependencyProperties are a more elaborate construct that supports default values, change notifications in a more memory-efficient and performant way.
The only relationship is that the WPF binding model supports binding to either DependencyProperties or to standard Clr properties, with an INotifyPropertyChanged implementation. Your ViewModel could be a DependecyObject as well and the third option would be to bind to the ViewModel's DependencyProperties!
Kent Boogaart wrote a very interesting article on having a ViewModel be a POCO vs a DependencyObject.
I don't really think there is a relationship between DependencyProperties and INotifyPropertyChanged. The only magic here is that the Binding classes/utils are smart enough to recognize a DependencyProperty and bind directly to it, or subscribe to the binding-target's notify-property-changed event and wait for that to fire.
With WPF, you can either bind to DependencyProperties or to Properties which implement INotifyPropertyChanged. It's a matter of choice.
So your question breaks into either to have them in code behind or in view model. Since you have mentioned that you do not want a tightly-coupled code behind, you are better off having a view model following the MVVM pattern.
You can use the DependencyProperties even in your view model just like you have done in your code behind.