Can anyone point me to a good resource (or throw me a clue) to show me how to do DataBinding to controls (ComboBox, ListBox, etc.) in WPF? I'm at a bit of a loss when all my WinForms niceities are taken away from me, and I'm not all that bright to start with...
The best resource I've found for WPF data binding is Bea Costa's blog. Start from the first post and read forward. It's awesome.
I find the tutorial videos at Windows Client .Net equally awesome. Dot Net Rocks TV has also covered it some time ago.
in code behind -- set the DataContext of your list box equal to the collection you're binding to.
private void OnInit(object sender, EventArgs e)
{
//myDataSet is some IEnumerable
// myListBox is a ListBox control.
// Set the DataContext of the ListBox to myDataSet
myListBox.DataContext = myDataSet;
}
In XAML, Listbox can declare which properties it binds to using the "Binding" syntax.
<ListBox Name="myListBox" Height="200"
ItemsSource="{Binding Path=BookTable}"
ItemTemplate ="{StaticResource BookItemTemplate}"/>
And some more links, just in case the above didn't suffice:
Windows Presentation Foundation - Data Binding How-to Topics
- Approx 30 'How To' articles from MSDN.
"The topics in this section describe how to use data binding to bind elements to data from a variety of data sources in the form of common language runtime (CLR) objects and XML. "
Moving Toward WPF Data Binding One Step at a Time
- By WPF guru Josh Smith
"This article explains the absolute basics of WPF data binding. It shows four different ways how to perform the same simple task. Each iteration moves closer to the most compact, XAML-only implementation possible. This article is for people with no experience in WPF data binding."
Here's another good resource from MSDN: Data Binding Overview.
There are three things you need to do:
Bind the ItemsSource of the ComboBox to the list of options.
Bind the SelectedItem to the property that holds the selection.
Set the ComboBox.ItemTemplate to a DataTemplate for a ComboBoxItem.
So, for example, if your data context object is a person having email addresses, and you want to choose their primary, you might have classes with these signatures:
public class EmailAddress
{
public string AddressAsString { get; set; }
}
public class Person
{
public IEnumerable<EmailAddress> EmailAddresses { get; }
public EmailAddress MainEmailAddress { get; set; }
}
Then you could create the combo box like this:
<ComboBox ItemsSource="{Binding EmailAddresses}" SelectedItem="{Binding MainEmailAddress}">
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding AddressAsString}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Now you need to implement INotifyPropertyChanged in both Person and EmailAddress. For the EmailAddresses collection, you could back it with an ObjservableCollection.
Or as an alternative you can use Update Controls .NET. This is an open source project that replaces data binding and does not require INotifyPropertyChanged. You can use whatever collection makes sense to back the EmailAddresses property. The XAML works the same as above, except that you import the UpdateControls.XAML namespace and replace {Binding ...} with {u:Update ...}.
Related
I am developing an Application with the following layout,
I have no knowledge of MVVM and I'm on a tight timeline.
The Red area on the right is a ContentControl.
The area on the left will be a sidebar for Navigation
My question is
should I follow this aproach
http://channs.blogspot.com/2010/09/wpf-navigation.html OR
should I use MVVM light / Prism OR
should I use WPF pages?
I am currently inclined to option 1. Are there any pros and cons to it?
Which option would you recommend ?
My application will always have only one developer i.e. Me and it will contain about 30 screens.
Since you're on a tight schedule and have no knowledge of MVVM (or Prism?), then you'll be way better off using options 3 and 1. From my experience, it takes devs a long time to get up to speed on MVVM and Prism. Certain things that are taken for granted, become much more difficult in the MVVM/Prism world.
With that being said, I'm a huge advocate of MVVM/Prism and feel that it's well worth the extra effort, especially for a project of your size. However, since you're pressured for time, don't bother, just do code-behind.
Prism takes time to learn, if you are on a tight deadline then I think you should just go with what you know, When you have time reading the prism book especially the section on navigation will be helpful.
Don't go with PRISM,that would be an overkill for such non complex apps. If you are familiar with DataBinding, that can save you a lot of time even without MVVM.Since you're in a hurry, I think you should go with what you already know and start learning MVVM at ease.Good luck
mvvm is not that hard. in your case you need first a mainviewmodel.
public class MainViewModel
{
private ICollectionView _myView {get;set;}
public ObservableCollection<MyModulWrapper> MyModules{get;set;}
public MyModulWrapper SelectedModul {get;set;}
public MainViewModel()
{
this.MyModules = new ObservableCollection<MyModulWrapper>();
//i use icollectionview because i often need sorting or filtering
this._myView = = CollectionViewSource.GetDefaultView(this.MyModules);
this._myView .CurrentChanged += (s, e) => { this.SelectedModul = this._myView .CurrentItem as MyModulWrapper; };
}
}
you have to fill(in any way - i use mef for my apps, but hardcoded its also ok) your collection with all modules(viewmodels) you wanna show on your top screen.
the MyModulWrapper just contain the viewmodel for your modul and a nice display name for your navigation.
public class MyModulWrapper
{
public string Displayname {get;set;}
public object Modul {get;set;}//instead of object you can take an interface or base class or whatever
}
now you have all to let the mainview run :) you just have to set the datacontext for the MainWindow to your MainViewModel.
mainwindow.xaml
<Window.Resources>
<!--for each viewmodel you wanna show create a datatemplate. so wpf knows how to render your viewmodel-->
<DataTemplate DataType={x:Type local:MyViewmodel4FirstButton>
<local:MyFirstButtonView />
</DataTemplate>
</Window.Resources>
<!-- for navigation -->
<ListBox ItemsSource="{Binding MyModules}"
SelectedItem="{Binding SelectedModul , Mode=OneWay}"
IsSynchronizedWithCurrentItem="true">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Displayname}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- all you need to show your selected modul - if you have a DATATEMPLATEs!! -->
<ContentControl Content="{Binding SelectedModul }"/>
all your viewmodels have to implement INotifyPropertyChanged of course, and raise it properly.
ps: code is written without IDE so ignore errors^^
I am working on a dynamic search view wherein clicking a button should add a new row containing 3 combobox and 2 textboxes.
How should I go about doing this?
If you really want to do mvvm , try to forget "how can I add controls". You don't have to, just think about your viewmodels - WPF create the contols for you :)
In your case lets say we have a SearchViewModel and a SearchEntryViewmodel.
public class SearchEntryViewmodel
{
//Properties for Binding to Combobox and Textbox goes here
}
public class SearchViewModel
{
public ObservableCollection<SearchEntryViewmodel> MySearchItems {get;set;}
public ICommand AddSearchItem {get;}
}
Till now you dont have to think about usercontrols/view. In your SearchView you create an ItemsControl and bind the ItemsSource to MySearchItems.
<ItemsControl ItemsSource="{Binding MySearchItems}"/>
You see now all of your SearchEntryViewmodels in the ItemsControl(just the ToString() atm).
To fit your requirements to show every SearchEntryViewmodel with 3Comboboxes and so on you just have to define a DataTemplate in your Resources
<DataTemplate DataType="{x:Type local:SearchEntryViewmodel}">
<StackPanel Orientation="Horizontal">
<Combobox ItemsSource="{Binding MyPropertyInSearchEntryViewmodel}"/>
<!-- the other controls with bindings -->
</StackPanel>
</DataTemplate>
That's all :) and you never have to think about "how can I add controls dynamically?". You just have to add new SearchEntryViewmodel to your collection.
This approach is called Viewmodel First and I think it's the easiest way to do MVVM.
One option is that you can create TextBoxes and comboboxes in backend by creating a new instanse.
But the better option is that you can create one usercontrol which contains All texboxes and comboboxes which you want to add and in which format you want.
After creating when the button is pressed you can create a instace of this usercontrol and set it in the grid or any other control by using SetValue property of the control.
If you are new to WPF and MVVM this read this blogs to understand this.
https://radhikakhacharia.wordpress.com/2012/06/01/wpf-tutorial-3/
https://radhikakhacharia.wordpress.com/2012/02/13/model-view-viewmodel/
If you are new to both MVVM and WPF, there is a really wonderful video tutorial on how to
architect a C# / WPF / MVVM application by Jason Dollinger which is available here on lab49. All of the sourcecode he developes in this amazing video is available also right here on lab49.
After watching it, you will not have any problems developing your search view for sure.
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).
Here is what i have:
a SQL CE database, that holds this Category table, with id and name columns only.
dbml generated with sqlmetal
singleton (static class) that exposes the linq DataContext.
in the code-behind file, i have a property like follows:
private System.Data.Linq.Table<Categories> Categories
{
get
{
return LibraryDataStore.Instance.Categories;
}
}
I want to simply bind the categories to a ComboBox. Can't believe i've been at it for hours now, with no result :(
I don't want to set ItemsSource in the code behind, I want to do this XAML-only, but how?
Most examples i found were defining the data right there in XAML, or setting ItemsSource programatically, but that is not what i want.
Why isn't this, for example, working?
<ComboBox Name="cmbCategory"
Margin="3"
MinWidth="200"
ItemsSource="{Binding Path=Categories}"
DisplayMemberPath="Name"/>
As a side note, i want to say that I find the databinding model of wpf extremely difficult to learn, as it is so thick and there are just SO MANY WAYS to do things.
Later edit:
I found that it works if i set the ItemsSource like this:
var cats = from c in LibraryDataStore.Instance.Categories
select c;
cmbCategory.ItemsSource = cats;
Still, I can't figure it out why it doesn't work in XAML.
You must set the datacontext of the UserControl to LibraryDataStore.Instance. This datacontext will then filter down the visual tree to your combobox (so there is no need to set the datacontext of the combobox itself). Your xaml will then be able to bind to the public property of this object "Categories".
Bea Stollnitz gives a good overview of how to detect problems with databinding (i.e. it failing silently) on her blog -> http://bea.stollnitz.com/blog/?p=52
you need to set the DataContext of your UserControl (or Page) to the current instance :
this.DataContext = this;
I have a ListBox whose ItemSource is an ObjectDataProvider that is an instance of an ObservableCollection. The ObservableCollection is a collection of ObservableCollections. The ItemTemplate of the ListBox is a DataTemplate that creates a ListBox for each item of the listbox. To illustrate this better I'm trying to recreate a card game in WPF. Basically, from a hand of cards you can create books. After you have a valid book, you can elect to make it a book which will go into the ObservableCollection of Books. The problem that I'm having is that each item of the ListBox is a ListBox that has an ItemSource that is a Book, that is an ObservableCollection of Cards. I don't think I'm having a problem with the source or the template of the outer ListBox, but I'm having a hard time understanding how I'm going to set the source of the ListBox items to the collection of cards for each book. Essentially, my question may be confusing and a difficult concept to grasp, but essentially I'm trying to figure out how to use a ListBox in a template that will be the template of another ListBox. If anyone has any idea of how to approach this, I would greatly appreciate hearing it.
With Card like the following:
public class Card
{
private string _name;
public Card(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
set { _name = value; }
}
}
and Book like the following:
public class Book
{
private readonly ObservableCollection<Card> _cards;
public Book(ObservableCollection<Card> cards)
{
_cards = cards;
}
public ObservableCollection<Card> Cards
{
get { return _cards; }
}
}
Then create your ListBox in the window:
<ListBox
ItemsSource="{Binding ElementName=Window, Path=Books}"
ItemTemplate="{StaticResource MainListTemplate}" />
and in the resources for the window put:
<Window.Resources>
<ResourceDictionary>
<DataTemplate
x:Key="InsideListTemplate">
<TextBlock
Text="{Binding Name}" />
</DataTemplate>
<DataTemplate
x:Key="MainListTemplate">
<ListBox
ItemsSource="{Binding Cards}"
ItemTemplate="{StaticResource InsideListTemplate}" />
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
Your ListBox uses the MainListTemplate, which contains a ListBox. The ItemsSource for that ListBox is your list of Cards, and the ItemTemplate is the InsideListTemplate. I have it as a simple TextBlock but you could do whatever you need.
Don't put a ListBox inside a ListBox, it will create a very confusing UI because you'll have several "levels" of selected items.
You can put an ItemsControl inside a ListBox if you need a single ListBox with a collection inside each item or a ListBox inside an ItemsControl if you need multiple list boxes.
Thank you for the responses. While I do agree with both responses, and always appreciate being notified of bad coding practices, the first answer did the trick. I was having an issue with the ItemsSource of the ListBox within my DataTemplate. Somewhere along the lines of learning WPF, I became hooked on using ObjectDataProvider(s) as my ItemsSource. Since the ObjectDataProvider was only an instance of the collection, and when I would update it the source of cards for all of my "Books" would be the same. Changing my ItemsSource binding source directly to the observable collection "Cards" did the trick.
Although it may be confusing in regards to the UI, I'm not sure that I'm going to even allow for the items in either of the lists to be selectable. My intentions were merely for a visual representation of the players books. I may need to allow for the items on the outer list to be selectable in able to move the cards from a book and back to the main hand but I'm not sure yet.
Thanks again for the help.
Thanks,
Brandon