Binding to a specific object in MVVM - wpf

In WPF using MVVM can we bind a textbox to a property of a specific instance , that is to one particular object ?

The short answer? Yes, what you are describing is kind of the purpose behind databinding.
Here is the extended answer in form of an example.
<Grid DataContext={Binding myViewModel}>
<TextBlock Text={Binding myTextProperty}/>
</Grid>
XAML.cs
public class Main{
public ViewModelObject myViewModel { get; set; }
public void Main(){
InitializeComponent();
myViewModel = new ViewModelObject();
this.DataContext = this;
}
}
ViewModelObject.cs
public class ViewModelObject{
public string myTextProperty{
get { return "It works!"; }
}
}
This will work. If you want a deeper example or understanding you need to research the following.
How WPF works
XAML
DataBinding
INotifiyPropertyChanged
MVVM

Related

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}" />

How to set datacontext for each combobox?

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;}
}

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.

Binding Enum[] to ListBox

I have next enumeration
Enum rcCategory
{
Incoming,
Internal,
Outgoing
}
and I have property "categories" in my class which has rcCategory[] type.
I would like to bind this property to the listBox. I use next code for this
MyListBox.SetBinding (ListBox.ItemsSource, new Binding {Source= myClass.categories});
But this code doesnt work as expected.
How Can I do this. My listBox always is empty but source property has value
See Bea Stollnitz top ranked article on it.
In short you need to bind to an ObjectProvider which calls the static method Enum.GetValues( typeof(YourEnum) ) to return the list.
http://bea.stollnitz.com/blog/?p=28
Update: Sorry got a slight speedreading issue. This one is easier.. Verified that it works. Recommended: Find up a copy of ProgrammingWPF and go thru the DataBinding chapter...
XAML:
<ListBox DockPanel.Dock="Left" ItemsSource="{Binding EnumArrayProp}"/>
Codebehind:
public partial class Window1 : Window
{
public rcCategory[] EnumArrayProp
{
get; set;
}
public Window1()
{
InitializeComponent();
this.EnumArrayProp = new rcCategory[] { rcCategory.Incoming, rcCategory.Incoming, rcCategory.Outgoing };
this.DataContext = this;
}

Resources