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;
}
Related
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
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.
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.
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.
Pretty simple task, but the source code doesn't do required job... Please advise.
There is Products collection in the class (approach is based on the MVVm pattern, but that is not influe on the current issue):
public class ProductWindowViewModel : WorkspaceViewModel // implements INotifyPropertyChanged
{
public ProductWindowViewModel()
{
Products = new List<Product>(ProductService.Instance.Repository.GetAll());
}
List<Product> Products { get; set; }
}
Here is class declaration:
public class Product : IEntity
{
#region Public Properties
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Cost { get; set; }
#endregion
}
The class instance is binded to the window's Grid data context:
ProductWindow wnd = new ProductWindow();
wnd.MainGrid.DataContext = new ProductWindowViewModel();
wnd.ShowDialog();
And here is xaml code of the window:
<Window x:Class="WpfTest1.ProductWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ProductWindow" Height="300" Width="300" xmlns:igDP="http://infragistics.com/DataPresenter"
xmlns:ViewModel="clr-namespace:ViewModel;assembly=ViewModel">
<Grid x:Name="MainGrid">
<Grid.Resources>
<ObjectDataProvider x:Key="odpObjectDataProvider" ObjectType="{x:Type ViewModel:ProductWindowViewModel}" />
</Grid.Resources>
<Grid DataContext="{StaticResource odpObjectDataProvider}">
<igDP:XamDataGrid DataSource="{Binding Path=Products}"/>
</Grid>
</Grid>
The xamDataGrid sampe is the same. overall code is pretty simple, but doesn't work.
Does anybody know why? Any thoughts are welcome.
How could I debug binding to resolve the problem himselft?
Thanks.
Ok, maybe this won't exactly answer your question, but it looks like you are instantiating your viewmodel class twice. Once in your code, immediately after creating your window, and once in the ObjectDataProvider thing. It will probably be easier to debug if you settle on one of them. Suggestion:
1. Comment out this line: wnd.MainGrid.DataContext = new ProductWindowViewModel();
2. Set a breakpoint inside the constructor of your viewmodel
3. Start it up and see if the breakpoint gets hit. If it does get hit, you know you are doing something right.
Also, check the output window in visual studio and see if any binding exceptions are reported there.
In my case the code in the windows constructor is redundant. Now all is working, seems like removing unnecessary assignement resolved an issue.