How to set datacontext for each combobox? - wpf

I'm having a problem about binding in combobox ( WPF, MVVM).
I have a combobox, which binds to AViewModel ( for example).
To do that, I did have:
- AModel
- AViewModel
- Xaml file :
<Window.DataContext>
<ViewModel:AViewModel/>
</Window.DataContext>
It works fine.
But, now, I add one more combobox to the same form with combobox above. This combobox binds to diffirent ViewModel (BViewMoel for example, note that, this BViewModel located in diffirent file with AViewModel above).
And this is combobox xaml:
<ComboBox
DataContext="BViewModel"
ItemsSource="{Binding Path=MyList}" DisplayMemberPath="BName"/>
My problem is: the second combobox is not populated because it does not have datacontext.
But I cannot set datacontext for it because it is set above for AViewModel.
I did a lots of searching but I still stuck in this.
Should I merge all ViewModels into a ViewModel and set this to Datacontext of Window or any ideal?
Thank you.

Really, I wouldn't use a ViewModel for each combobox. Combobox is a simple control, you should bind the ItemsSource property to a public property (of type ObservableCollection<T> for instance) of the ViewModel of the owner view.
Sometimes it's useful to use a ViewModel for a specific and complex usercontrol. In this case, you can expose the viewModel as a public property of the ViewModel of the owner view:
public class UCViewModel : ViewModelBase
{
}
public class MyViewViewModel : ViewModelBase
{
public MyViewViewModel()
{
this.UCViewModel = new UCViewModel();
}
public UCViewModel UCViewModel { get; set; }
}
<Window x:Class="MyView">
<MyComplexUsercontrol DataContext="{Binding UCViewModel}" />
</Window>
public partial class MyView : Window
{
public MyView()
{
InitializeComponent();
this.DataContext = new MyViewViewModel();
}
}
But again, for a simple combobox, just bind it to a property of the ViewModel associated with the owner view.

combobox1.DataContext = new AViewModel();
combobox2.DataContext = new BViewModel();
But I suggest using a ViewModel contains two properties.
public class ViewModel
{
public AViewModel AViewModel{get;set;}
public BViewModel BViewModel{get;set;}
}

Related

WPF: Binding listview itemsource from viewmodel in MVVM [duplicate]

This question already has an answer here:
Creating and binding buttons dynamically in a WrapPanel
(1 answer)
Closed 5 years ago.
I am trying to set ItemSource property for listview without success.
View (xaml):
<ListView Margin="10" Name="MyLv" ItemsSource="{Binding}">
....
</ListView>
Code-Behind Constructor (xaml.cs):
public MyView()
{
InitializeComponent();
}
ViewModel:
private List<DataModel> lstData = null;
public MyViewModel()
{
this.lstData = this.LoadData(); // this connects to a database an extract info to be loaded in listview
}
Data Model:
public class DataModel
{
public bool IsSelected { get; set; }
public string ID { get; set; }
public string Desc { get; set; }
}
Before this, I was loading the listview from code-behind and it was working, but now I want to load it from my viewmodel and I do not know how can I make it work.
Based on the code you posted, there are a couple of problems:
You haven't set the DataContext of the view. You typically want to set this to an instance of your view model class.
The ViewModel doesn't expose the list as a public property. WPF bindings only work on public properties. The ItemsSource should be bound to this property, and not to the DataContext itself.
Finally, you probably want the collection in the ViewModel to be an ObservableCollection. This way, when changes are made to the collection, the list in the UI will be automatically updated.

Confused in DataContext in WPF

I am beginner to WPF and MVMM architecture. VI came across many links which explains about DataContext dependence property in WPF MVMM architecture,
i.e.
view.DataContext = new ViewModels.MainViewModel();
but they always made me confused. Although I have some basic idea about this DataContext like it is used to represent who's object we need in xaml file, but when blogs talks about tree structure inheritance of dataContext I gets confused. Can any one please help me with some very simple and clear example showing how this hierarchy of DataContext works?
Thanks in advanced.
The DataContext property specifies the default source for Data Binding. Consider the following example:
<TextBox Text="{Binding MyProperty}" />
What this Binding says: take the value of MyProperty from whatever object is inside the DataContext, convert it to a string and put it in the TextBox. So if we would set the DataContext of the TextBox to be an object of the following class:
public class Example {
int MyProperty { get { return 3; } }
}
Then, the Text of the TextBox would be set to 3.
What does it mean that the values Inherit? Consider a slightly more complex example:
<Window Name="MainWindow">
<StackPanel>
<TextBox Text="{Binding MyProperty}" />
...etc
If we would have 10 or more TextBox elements on our screen, it would be a lot of senseless work to assign the DataContext to each and every TextBox. To relieve this issue, the implementors of WPF decided that setting the DataContext on the MainWindow in our case would also apply it to everything inside that Window (all children, all nested elements) until the DataContext property is overwritten (i.e. we set the DataContext of the TextBox, then the TextBox and all its children would also receive this DataContext).
If you want to see this behavior in action, the same applies to the FontSize property, try setting the FontSize of your Window to 48 and see what happens to all the text in there!
The Datacontext property is the default source of all the binding of a View.
In MVVM, the Datacontext is used to link a ViewModel to a View.
As the Datacontext property is a dependence property, if you don't define it in a control, it will inherit from his father, etc.
Here is an exemple of MVVM implementation :
Parent of all ViewModel class (to implement INotifyPropertyChanged in all ViewModels) :
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Note : INotifyPropertyChanged allow your ViewModel to notify the View of a change (used for bindings).
Let's say I want a MainWindows (View) to be linked to a ViewModel :
public MainWindow()
{
InitializeComponent();
MainViewModel mainViewModel = new MainViewModel(this);
this.DataContext = mainViewModel;
}
With for ViewModel :
class MainViewModel : ViewModelBase
{
#region fields
private MainWindow mainWindow;
private string message = "Hello world !";
#endregion
#region properties
public MainWindow MainWindow
{
get
{
return this.mainWindow;
}
}
public string Message
{
get
{
return message;
}
set
{
this.message = value; OnPropertyChanged("Message");
}
}
// ...
#endregion
public MainViewModel(MainWindow mainWindow)
{
this.mainWindow = mainWindow;
}
}
So now if I want to bind a property of MainViewModel in my View (mainwindow), i just have to have a public property in my ViewModel and to create a binding in my XAML. I won't have to specify the source as the DataContext is the default source.
So MainWindow.xaml I can add :
<TextBox Text="{Binding Message}" />

Adding databing to a datagrid?

I have a simple datastructure following:
In the model I have
public class Receipt
{
public int Id { get; set; }
public double Price { get; set; }
public string Store { get; set; }
public DateTime Date { get; set; }
}
I've made two of these objects and I am trying to bind them to a datagrid. I've filled in the properties of the two receipts and added them to the dataGridRows but they don't show up in my DataGrid.
public MainWindow()
{
InitializeComponent();
makeReceipts()
}
public ObservableCollection<Receipt> dataGridRows = new ObservableCollection<Receipt>();
public Receipt receipt1 = new Receipt();
public Receipt receipt2 = new Receipt();
public void makeReceipts()
{
receipt1.Id = 1;
receipt1.Price = 10;
receipt1.Store = "Brugsen";
receipt1.Date = DateTime.Today;
receipt2.Id = 2;
receipt2.Price = 15;
receipt2.Store = "Netto";
receipt2.Date = DateTime.Today;
dataGridRows.Add(receipt1);
dataGridRows.Add(receipt2);
}
And in the xaml of the MainWindow where I want my datagrid to display the receipts I have:
<DataGrid Name="ReceiptGrid" CanUserResizeColumns="True" IsReadOnly="True" AutoGenerateColumns="True" ItemsSource="{Binding Source=dataGridRows}" />
What am I doing wrong?
first you can just bind to public properties.
so if you want to use binding you have at least do:
public ObservableCollection<Receipt> dataGridRows {get;set;}
second you have to do two steps:
set the right datacontext
set the right binding expression(Path)
assume that the datacontext for yyour grid is an object with the property dataGridRows, your binding should look like this
<DataGrid ItemsSource="{Binding Path=dataGridRows}" .../>
Think your problem is you have to write
ItemsSource="{Binding Path=dataGridRows}"
and not
ItemsSource="{Binding Source=dataGridRows}"
source is to specify another control in xaml file
First of all you can bind only public properites so you need to change definition of dataGridRows to something like this:
public ObservableCollection<Receipt> dataGridRows { get; set; }
then you don't bind it as a Source but as a Path, however since your dataGridRows is defined in MainWindow you need to specify Source as your MainWindow otherwise it will look in default DataContext which is not set in your case
<DataGrid ... ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=dataGridRows}" />
this tells Binding to find Window and look for a dataGridRows property there.EDIT:Normally you don't put data into view. I suggest you read more about MVVM design pattern but basically the idea is that you have your ViewModel where you put in you whole application logic, unaware of interface, and then on top you have your view to interact with user but in ViewModel you don't operate on controls.What you should do is create your view-model class with dataGridRows property and assign it through DataContext of Window for example. Each FrameworkElement has it and when you don't specify Binging source (Source, RelativeSource, ElementName) it will try to resolve Binding.Path in current DataContext. If current control does not have it specified then if will go to parent in visual tree and so on.

Binding a save command WPF

I have a window with 3 textboxes in a grid -this is my view- and I have Save button to add a new user to my user list with the datas from the textboxes.
I want to use a relay command to do this on my viewmodel class but I am quite confused with how to make the bindings. I hope it's clear enough. Any ideas, or examples will be helpful.
thanks in advance.
You should have a ViewModel something like the following :
class UserViewModel
{
public String Name { get; set; }
public String Password { get; set; }
public String Email { get; set; }
public RelayCommand AddUserCommand { get; set; }
public UserViewModel()
{
AddUserCommand = new RelayCommand(AddUser);
}
void AddUser(object parameter)
{
// Code to add user here.
}
}
And you can use it like following :
<StackPanel>
<TextBox Text="{Binding Name}"></TextBox>
<TextBox Text="{Binding Password}"></TextBox>
<TextBox Text="{Binding Email}"></TextBox>
<Button Command="{Binding AddUserCommand}">Add</Button>
</StackPanel>
To make this work, put following code in your UserControl/Control/Window's constructor :
DataContext = new UserViewModel();
I presume that you read Josh Smith article: WPF Apps With The Model-View-ViewModel Design Pattern. If you didn't, then read it first, and then download code, because example is very similar to your problem.
Did you created an instance of the ViewModel and putted this instance in the DataContext of your view or stackpanel?
example:
UserViewModel viewModel = new UserViewModel();
UserWindow view = new UserWindow();
view.DataContext = viewModel;
view.Show();
There are several options on coupling the View and the Viewmodel:
Create the View and ViewModel and set the ViewModel to the DataContext property (code above)
Create the ViewModel in the constructor of the View and fill the DataContext property with it
Create a Resource in your view of the type of your ViewModel and fill the DataContext property in XAML
I prefer the first option because you can combine the Views and Viewmodels as you like at runtime.
Hopefully this is a helpfull answer.

XAML Binding to a CollectionViewSource property on a ViewModel

I have a simple ViewModel like:
public class MainViewModel {
ObservableCollection<Project> _projects;
public MainViewModel() {
// Fill _projects from DB here...
ProjectList.Source = _projects;
ProjectList.Filter = ...;
}
public CollectionViewSource ProjectList { get; set; }
}
I set the window's DataContext to a new instance of that ViewModel in the constructor:
public MainWindow() {
this.DataContext = new MainViewModel();
}
Then in the Xaml I am attempting to bind the ItemsSource of a ListBox to that ProjectList property.
Binding just ItemsSource like so doesn't work:
<ListBox ItemsSource="{Binding ProjectList}" ItemTemplate="..." />
But if I first rebase the DataContext this works:
<ListBox DataContext="{Binding ProjectList}" ItemsSource="{Binding}" ItemTemplate="..." />
Shouldn't the first method work properly? What might I be doing wrong?
If you are using CollectionViewSource you need to bind ItemsSource to ProjectList.View instead of ProjectList. That should solve your problem.
From what you provided the first method should perfectly work. Devil lurks somewhere in details.
PS: Maybe you didn't specify implementation of INotifyPropertyChanged interface in sake of post size, but be careful in production. It's very easy to get a memory leak if you don't implement it.

Resources