XAML Binding to a CollectionViewSource property on a ViewModel - wpf

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.

Related

How to use IObservable<T> as a source for a WPF source binding to a ListBox?

So this is what I am currently doing:
I have a WPF ListBox that is currently data bounded to and populated by a
public ObservableCollection<string> SourceBinding
{
get;
set;
}
This WPF bounded source has an OnCollectionChanged event handler that does the following whenever a new item is added;
ObservableCollection<string> source = new ObservableCollection<String>();
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
NotifyPropertyChanged("NotifyPropertyChanged")
}
I am also subscribed to an IObservable<string> stream that is handling each tick via the TickHHandler event handler;
Stream.Subscribe(TickHandler);
TickHandler is currently doigng this:
private void TestSubscription( string item)
{
sourceBinding.Add(item)
}
Here, for each output tick event from the Rx stream, the ObservableCollection is updated and the WPF GUI is notified of the changes that need to be made.
What I would like to do however, is bind the ListBox directly to my IObservable<string> stream preferably inside xaml.
I am assuming that I'd somehow have to use Behaviors to expose a custom IObservableItemsSource property to bind the IObservable<string> source for consumption. I imagine it would look something like this in the end:
IObservableItemsSource ="{Binding IObservableSource}"
I know how to implement Behavior, but I have no idea how to start creating an IObservable<string> property for use in xaml, or if this is even possible!
Am I way off the mark? Can someone explain what the best way to implement this should be?
Thanks.
The Observable Collection implement INotifyCollectionChanged which will alert the xaml that it needs to update the view. So if you just add to the collection as you are doing it should update the UI automatically as long as you are binding it correctly to the ViewModel.
This is the view
<ListBox ItemsSource="{Binding Collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is the code behind
public class ViewModel
{
public ObservableCollection<string> Collection { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
vm.Collection = new ObservableCollection<string>();
this.DataContext = vm;
vm.Collection.Add("Item");
vm.Collection.Add("Item");
vm.Collection.Add("Item");
vm.Collection.Add("Item");
vm.Collection.Add("Item");
}
Note that as long as you are doing your processing in the UI thread you this will work. If you are doing it in a background thread you will need to dispatch and add to the observable collection in the UI thread.

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.

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