How to initialise my WPF app using MVVMLight? - wpf

I am building a WPF application using MVVM Light and having problems tying up my Views to my View Model. I have a view model in which I am passing in an Interface of IDataContext, which is basically passing in a datacontext.Then I have an View which I have inserted the following statement on top
DataContext="{Binding MyViewModel, Source={StaticResource Locator}}"
In my ViewModelLocator I have added the following lines :
IoC.Register<IDataContext, MyDataContext>();
and
IoC.Register<MyViewModel>();
And after putting a break point in the constructor of the 'MyViewModel', the breakpoint gets hit. Is there something I am missing, please help???

Did you define a public getter for your viewModel in ViewModelLocator class as shown below?
public MyViewModel MainViewModel
{
get
{
return SimpleIoc.Default.GetInstance<MyViewModel>();
}
}
and then use the "MainViewModel" in the view binding as shown below
DataContext="{Binding MainViewModel, Source={StaticResource Locator}}"
What kind of behavior you see? Empty view window with no datacontext set? OR exception when displaying your view?

You can have a look at this http://nileshgule.blogspot.com/2011/05/integrate-mvvmlight-toolkit-with-basic.html

Related

WPF mvvm DataTemplates change View from UserControl

I am new to WPF and the MVVM pattern. I am trying to build a 'step by step' or 'wizard' like application.
So the user should first login then select some data and finally the selected data should be stored somewhere. (This flow never changes!)
However I decided to use DataTemplates and different ViewModels for each Template and a MainViewModel for the Window which populates the Templates. (Think this should be ok regarding to different Posts here)
But now my problems are starting. I know how I can change the current view from the MainViewModel BUT I want to change the current View from the inner ViewModel. And I want to be able to collect data from one inner ViewModel to another and I have no clue how this can work.
MainViewModel:
public class MainWindowViewModel : ViewModelBase
{
public ViewModelBase CurrentView {get; set;}
public MainWindowViewModel()
{
CurrentView = new ViewModelA;
}
}
XAML:
<Window x:Class="PUSEImporter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:PUSEImporter.ViewModel"
xmlns:V="clr-namespace:PUSEImporter.View">
<Window.DataContext>
<VM:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type VM:ViewModelA}">
<V:Detail />
</DataTemplate>
<DataTemplate DataType="{x:Type VM:ViewModelB}">
<V:Overview />
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding CurrentView}"/>
</Window>
So think about a button in ViewModelA (or the View from ViewModelA) and now I want to switch to ViewModelB when someone clicks on the button. And not enough the data which is collected by ViewModelA should also be available in ViewModelB.
Is this possible and the preferred way of using this techniques or do I misunderstand some concepts?
(And if this is true how should i handle things like that?)
Thanks in advance!
There are many ways to achieve what you want. In MVVM, there's one view model to each view... therefore, if your main view has a child view, then your main view model should have a property of the type of another view model. In this instance, you can add a delegate to the child view model and register a handler for it in the main view model.
This will enable you to effectively pass a signal to the main view model from the child view model, which you can react to in the parent view model in any way you want to. Rather than explain the whole story again here, please see my answers from the Passing parameters between viewmodels and How to call functions in a main view model from other view models? posts here on Stack Overflow for more information on how to achieve this.

How can I set ComboBox DataContext in XAML?

I am trying to understand Binding so I have come up with a very simple program to try and test it.
I have the following element in my MainWindow:
<ComboBox Name="comboBox1" ItemsSource="{Binding}" />
In my Code I have the following observable collection:
public ObservableCollection<string> ComboItems = new ObservableCollection<string>();
I can successfully add items this way at any point during runtime:
comboBox1.DataContext = ComboItems;
ComboItems.Clea();
ComboItems.Add("Item");
My question is, how could I set the DataContext in XAML so that I don't have to do it in code? Is it possible?
Thank you!
Something common is:
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}">
<ComboBox ItemsSource="{Binding ComboItems}" .../>
However usually you want to inject another object instance as DataContext, have a look at the MVVM pattern for example. Properties in WPF are inherited, so the ComboBox has the DataContext of the Window, it can be overwritten at any level though.
Note: For the Binding to work ComboItems needs to be a public property, not a field.
Resources of interest:
Data Binding Overview
Data Templating Overview
Depedency Properties Overview

How do I bind a "list" of strings to a ComboBox in WPF?

I basically want to take a bunch of names in a collection and bind them to a combobox. For example:
Bill
Jack
Bob
Kevin
and have those items in a collection and have it bound to the ComboBox. I'm not sure if the list will be updated dynamically or not, but I prefer to plan for it to be. Any help would be appreciated. I've been trying for a few hours now and can't figure it out. I want to do it in XAML and not the code-behind. In the code-behind,
MyComboBox.ItemsSource = MyObservableCollection;
works fine. I don't know how to do that in XAML though with the collection declared in the code-behind.
Thanks in advance (again), community.
*EDIT:
This is how I have the collection declared and accessible.
public ObservableCollection<string> propertynames
{
get {return _propertynames;}
}
private ObservableCollection<string> _propertynames;
The last thing I tried was this:
<Window.Resources>
<CollectionViewSource Source="{Binding propertynames}" x:Key="srcSort"/>
</Window.Resources>
....
<ComboBox x:Name="cboSort" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="256" Background="WhiteSmoke" Margin="12,50,0,0" FontSize="12pt"
Height="27.28"
SelectedIndex="0"
SelectionChanged="cboWorkCenters_SelectionChanged"
ItemsSource="{Binding Path = {StaticResource srcSort}}">
</ComboBox>
....
I'm a total n00b to this stuff. Been in it about a week now, so I may have done something really obvious to a seasoned user.
*EDIT #2
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:WpfApplication1"
Title="Window1" Height="226" Width="242"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<ComboBox Margin="43,71,40,77"
Name="comboBox1"
ItemsSource="{Binding ob}" />
</Grid>
</Window>
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public ObservableCollection<string> ob
{
get
{
return _ob;
}
}
private ObservableCollection<string> _ob = new ObservableCollection<string>();
public Window1()
{
InitializeComponent();
FillObj();
//comboBox1.ItemsSource = ob;
}
private void FillObj()
{
for (int i = 1; i < 6; i++)
{
_ob.Add(i.ToString());
}
}
}
}
Made above real simple project just to see if I was doing it all wrong. This worked fine so something else must be causing it to fail.
*EDIT #3
*PROBLEM FIXED
For God's sake, I figured it out. I've been on this for HOURS and it's just silly what's caused it to fail.
The solution is this: I wasn't instantiating _propertynames when I declared it. I was querying the class properties with Linq to get the list of properties and then created _propertynames by passing ...GetProperties.ToList<...>() to the constructor. Apparently, you have to instantiate the variable so it hits during InitializeComponent. Unreal.
Once I did that and then added the items to it after the fact, it worked fine.
I wish WPF had a face so I could punch it. I know it's my ignorance of how it works, but I really could have used some kind of message.
Thanks guys for the help. Both of your suggestions were useful once I took care of the root issue.
private ObservableCollection<string> _propertynames
needs to be
private ObservableCollection<string> _propertynames = new ObservableCollection<string>()
There are countless ways of doing this. Once you've created the collection in code-behind, you can:
Call Resources.Add to add it to the window's resource dictionary, and then bind to the resource, e.g. ItemsSource="{Binding {DynamicResource MyList}}".
Give the ComboBox a name (using the x:Name attribute) and set its ItemsSource explicitly in code, e.g. MyComboBox.ItemsSource = myCollection;.
Create a class, make the collection a property of the class, and set the window's DataContext to an instance of that class and bind to it directly, e.g. ItemsSource = "{Binding MyCollectionProperty}".
Make the collection a property of the window, set the window's DataContext to this, and bind to the property (this is essentially the same technique as #3, only you're not creating a new class).
Without setting the window's DataContext, you can still reference a property on it using binding as long as you've given it a name, e.g. {Binding ElementName=MyWindow, Path=MyCollection}. (This is the same as Ross's suggestion.)
Or, without giving the window a name, you can use RelativeSource binding to find the ancestor Window and bind to a property on it. I don't have any confidence in my ability to write a working binding expression that uses RelativeSource off the top of my head, so I'll leave that as an exercise for the reader.
You can set the DataContext of the ComboBox to the instance of your collection, and then set itsItemsSource to {Binding}. You probably wouldn't do this in practice; I mention it just because it seems to be a common mistake for people to set the DataContext of a control without also setting a binding, and then wonder why content from the bound object isn't showing up.
(While I've said "window" in the above, everything I've said is also true for user controls.)
I'm sure there are at least five other ways to do this that I'm not thinking of. Binding is really, really flexible.
What have you tried so far?
I would approach it as follows, assuming the combo box is within a UserControl with a code-behind class containing the public property MyObservableCollection:
<UserControl x:Name="MyCollectionOwnerControl">
<ComboBox ItemsSource="{Binding ElementName=MyCollectionOwnerControl, Path=MyObservableCollection, Mode=OneWay}" />
</UserControl>

how to build dynamic grid and binding to xaml using mvvm

I'm planning a WPF application which will build dynamic grid with textblocks in the viewmodel and then refresh interface (xaml) with the new grid.
I've done the firts step, but i have problems to refresh the view with the new grid.
Is there any example code of how to bind the grid to the xaml that I can have a look at?? I really can't figure this out!
Thanks
You may be approaching this slightly wrongly, hard to say from the question-
Generally to show a dynamic set of UI elements in MVVM you bind the ItemsSource property of an ItemsControl to an ObservableCollection. The ItemsControl ItemsTemplate property converts the YourViewModel object into a UIElement which can be a TextBlock or whatever style you want.
So as an example:
// model
class Person
{
public string Name {get; private set;}
}
// view model
class MainViewModel
{
public ObservableCollection<Person> People {get; private set;}
}
//view
<UserControl DataContext="{Binding MyMainViewModelObject}">
<ItemsControl ItemsSource="{Binding People}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>/
</ItemsControl.ItemsTemplate>
</ItemsControl>
</UserControl>
I havent tested that code, it is just to illustrate. There are other ways of dissecting the problem into MVVM, it all depends on the situation. You would have to give more details for us to help you out with that. Rarely in WPF is there a need to use code to create or add UI elements to other UIElements etc.
A point to note more along the exact lines of the question however is that an ItemsControl can either bind to a bunch of regular objects and use it's template to create UIElements from them, OR it can bind to a list of UIElements, in which case the template is not applied (sounds like this is the situation you have).

loading a silverlight control with a custom constructor

I have a silverlight page in which I am loading a control. This control has its own viewmodel which I pass in to the .xaml.cs file thru its constructor. However I get an error when compiling. This is the error:
{No matching constructor found on type 'MySite.Views.SearchFlyOutWin'}
My main page makes a reference to the 'SearchFlyOutWin' like this
xmlns:part="clr-namespace:MySite.Views;assembly=MySite"
In my mainpage.xaml I have tried to load the control like this
<part:SearchFlyOutWin x:Name="searchFlyOutWin" Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}, Path=IsSearchVisible}" />
The constructor in my SearchFlyOutWin.xaml.cs is like this
public SearchFlyOutWin(ISearchFlyoutViewModel viewmodel)
{
InitializeComponent();
DataContext = viewmodel;
}
I get the error described above in my Mainpage.xaml.cs when it calls the InitializeComponent(); method.
I think I probably need to direct the clr to call the correct constructor when loading the searchwin in this line here below
<part:SearchFlyOutWin x:Name="searchFlyOutWin" Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}, Path=IsSearchVisible}" />
Any ideas on how to correct this? ...Thanks for your time.
.
I have a silverlight page in which I
am loading a control. This control has
its own viewmodel which I pass in to
the .xaml.cs file thru its
constructor. However I get an error
when compiling. This is the error:
{No matching constructor found on type
'MySite.Views.SearchFlyOutWin'}
If your own control's constructor takes some parameter(s), then you cannot use this control in XAML. In XAML, every control must have a constructor with no parameter. That is why, it shows the error message {No matching constructor found on type 'MySite.Views.SearchFlyOutWin'}, since XAML parser searches a constructor with no parameter in your control called SearchFlyOutWin, and it found none!
One soution is that remove the parameter from constructor, and define your Model in the XAML as resource, then set the DataContext to it. Like this,
<Window.Resources>
<local:SearchFlyoutViewModel x:Key="model"/>
</Window.Resources>
<part:SearchFlyOutWin DataContext="{StaticResource model}"/>
Hope, it solves your problem.
.
If you're committed to passing the viewmodel to the object in the constructor (which I don't think is a bad thing), the only way I've found to do this is to create the object in code and then add it to its parent panel programatically. Setting up bindings in code is also possible, though the syntax is more complex than the XAML syntax. The code might looks something like:
SearchFlyOutWin searchFlyOutWin = new SearchFlyOutWin(viewModel);
Binding b = new Binding("");
b.Source = IsSearchVisible;
b.Converter = new BooleanToVisibilityConverter();
searchFlyOutWin.SetBinding(SearchFlyOutWin.VisibilityProperty, b);
SearchFlyOutWinParentPanel.Children.Add(searchFlyOutWin);
Where SearchFlyOutWinParentPanel is some panel that can accept children. If there's an alternate way to do this in XAML, I'd love to see it, but I haven't found it yet.
You may need to set you viewmodel class to be public.
Because I guess your viewmodel class will be in another namespace other than view.

Resources