I have a collection of custom objects and i want to bind the index property of the ItemsControl to one of the int property in my custom object. how do i define such binding in the template? do i need a converter? any suggestions? thanks
First problem: ItemsControl doesn't have an Index or SelectedIndex property. For that, you need something that derives from Selector (like ComboBox, ListBox, etc.).
In that case, you can accomplish what you want easily using the SelectedValue and SelectedValuePath properties.
public class MyCustomObject {
public int CustomObjectIndex {get;set;}
}
public class ViewModel : INotifyPropertyChanged {
public IEnumerable<MyCustomObject> Items {get { return something;} }
// Setting this must raise PropertyChanged.
public int SelectedIndex {get; set; }
}
<ComboBox ItemsSource={Binding Items}
SelectedValue={Binding SelectedIndex, Mode=TwoWay}
SelectedValuePath="CustomObjectIndex" />
what you want to do doesnt make sense...
imagine you have a custom object with properties (name, wishedIndex) (wishedIndex as integer or whatever other magic to evaluate the wished index)
and now you have several of these objects --> several of wished indices.
Somewhere in your architecture you made a bad design choice. if you post more code we can find out
Related
Is it possible to bind to a value in Properties.Settings.Default in a way that will keep my UI current with the value stored there?
I have a class:
public class FavoritePlayer
{
public string Name
{
get
{
return wpfSample021.Properties.Settings.Default.FavoritePlayer.ToString();
}
set
{
wpfSample021.Properties.Settings.Default.FavoritePlayer = value;
}
}
}
In my XAML, I have a resource:
<local:FavoritePlayer x:Key="fvPlayer"/>
and a binding:
<Label DataContext="{DynamicResource fvPlayer}" Content="{Binding Path=Name}"/>
What I would like is for the data-binding to update any time the property is changed. Is there a way to do this?
Conveniently for you, ApplicationSettingsBase implements INotifyPropertyChanged so you just need to subscribe to PropertyChanged on Properties.Settings.Default and raise your own PropertyChanged in response.
You need your properties to implement INotifyPropertyChanged in order for bindings to recognise when the property value changes.
First of all, what I'm trying to do is a "simple" binding of a ComboBox to my source.
The structure is something like:
public class Data
{
public ObservableList<string> List {get;set;}
public string Selected {get;set;}
}
Also, it implements INotifyPropertyChanged interface.
My problem is, i found several solutions to do this via XAML, unfortunately i can't do it with XAML since my ComboBoxes have to be generated during runtime.
So my question is, how i can bind my ComboBox to Data.List, and also the selected item (value?) to Data.Selected, and this one should be TwoWay so my Data class knows that something was selected. Keep in mind this has to be through c# code (XAML is no option unfortunately).
Thanks in advance. :)
It's pretty easy. Assuming, that Data has properties instead of fields:
public class Data
{
public Data()
{
List = new ObservableCollection<string>
{
"Apple", "Orange", "Lime"
};
}
public ObservableCollection<string> List { get; private set; }
public string Selected { get; set; }
}
you can write this:
var comboBox = new ComboBox
{
DataContext = new Data()
};
comboBox.SetBinding(ComboBox.ItemsSourceProperty, new Binding("List"));
comboBox.SetBinding(ComboBox.SelectedItemProperty, new Binding("Selected")
{
Mode = BindingMode.TwoWay
});
To add ComboBox into visual tree, just call proper method for the container. E.g., this will work with any ContentControl (like Window):
AddChild(comboBox);
how i can bind my combobox to Data.List, and also the selected item (value?)
Create a custom composite user control which contains the combobox. Map the combobox's properties to two dependencies properties created on the custom control, one to load the data and the other to provide an on demand selected item's data. Any plumbing needs are done inside the codebehind which ultimately provides all the magic.
Then you can create/bind this control dynamically in codebehind as needed in the other page you are working on.
Sounds like a sort of "recursive binding". If your combos are in a container control, what you need is bound the container to a collection of your single combo model, so each view in the ItemsControl will be bound to a single combo model.
I have a ComboBox with few static values.
<ComboBox Name="cmbBoxField" Grid.Column="4" Grid.Row="2" Style="{StaticResource comboBoxStyleFixedWidth}" ItemsSource="{Binding}" ></ComboBox>
MVVMModle1.cmbBoxField.Items.Add(new CustomComboBoxItem("Text Box", "0"));
MVVMModle1.cmbBoxFieldType.Items.Add(new CustomComboBoxItem("Pick List", "1"));
MVVMModle1.cmbBoxFieldType.Items.Add(new CustomComboBoxItem("Check Box", "2"));
MVVMModle1.cmbBoxFieldType.Items.Add(new CustomComboBoxItem("Radio Button", "3"));
When I am saving the data in Database table it is getting saved.
((CustomComboBoxItem)(MVVMModle1.cmbBoxField.SelectedValue)).Value.ToString();
Now when I am trying to Edit my form and binding the value again to combobox it is not showing the value.
MVVMModle1.cmbBoxField.SelectedValue = dtDataList.Rows[0]["ControlList"].ToString().Trim();
Someone please help me in this. How to bind selected value to the combobox?
There are quite a few problems with your code here:
You are setting the ItemsControl.ItemsSource property to the default binding (bind to the current data context), which is incorrect unless the DataContext is any type that implements IEnumerable, which it probably isn't.
If this is correct because the DataContext is, for example, an ObservableCollection<T>, then you still have an issue because you are adding items statically to the ComboBox instead of whatever the ItemsSource is.
Also, the type of items you are adding are CustomComboBoxItem, which I'm going to assume inherits from ComboBoxItem. Either way, you can't say the SelectedValue is some string since the values in the ComboBox are not strings.
You should really not have a collection of CustomComboBoxItem's, but instead a custom class that is in itself it's own ViewModel.
Now that that's been said, here is a suggested solution to your problem:
<ComboBox ItemsSource="{Binding Path=MyCollection}"
SelectedValue="{Binding Path=MySelectedString}"
SelectedValuePath="StringProp" />
public class CustomComboBoxItem : ComboBoxItem
{
// Not sure what the property name is...
public string StringProp { get; set; }
...
}
// I'm assuming you don't have a separate ViewModel class and you're using
// the actual window/page as your ViewModel (which you shouldn't do...)
public class MyWPFWindow : Window, INotifyPropertyChanged
{
public MyWPFWindow()
{
MyCollection = new ObservableCollection<CustomComboBoxItem>();
// Add values somewhere in code, doesn't have to be here...
MyCollection.Add(new CustomComboBoxItem("Text Box", "0"));
etc ...
InitializeComponent();
}
public ObservableCollection<CustomComboBoxItem> MyCollection
{
get;
private set;
}
private string _mySelectedString;
public string MySelectedString
{
get { return _mySelectedString; }
set
{
if (String.Equals(value, _mySelectedString)) return;
_mySelectedString = value;
RaisePropertyChanged("MySelectedString");
}
}
public void GetStringFromDb()
{
// ...
MySelectedString = dtDataList.Rows[0]["ControlList"].ToString().Trim();
}
}
You could alternatively not implement INotifyPropertyChanged and use a DependencyProperty for your MySelectedString property, but using INPC is the preferred way. Anyways, that should give you enough information to know which direction to head in...
TL;DR;
Take advantage of binding to an ObservableCollection<T> (create a property for this).
Add your items (CustomComboBoxItems) to the ObservableCollection<T>.
Bind the ItemsSource to the new collection property you created.
Bind the SelectedValue to some string property you create (take advantage of INPC).
Set the SelectedValuePath to the path of the string property name of your CustomComboBoxItem.
Can you use cmbBoxField.DataBoundItem()? If not target the source from the selected value, i.e. Get the ID then query the source again to get the data.
(CustomComboBoxItem)MVVMModle1.cmbBoxField.DataBoundItem();
When you bind a datasource it is simpler to do it like this:
private List GetItems(){
List<CustomComboBoxItem> items = new List<CustomComboBoxItem>();
items.Add(new CustomComboBoxItem() {Prop1 = "Text Box", Prop2 = "0"});
//...and so on
return items;
}
Then in your main code:
List<CustomComboBoxItem> items = this.GetItems();
MVVMModle1.cmbBoxField.DisplayMember = Prop1;
MVVMModle1.cmbBoxField.ValueMember = Prop2;
MVVMModle1.cmbBoxField.DataSource = items;
This will then allow your selected value to work, either select by index, value or text
var selected = dtDataList.Rows[0]["ControlList"].ToString().Trim();
MVVMModle1.cmbBoxField.SelectedValue = selected;
I'm binding a GridView to a collection of objects that look like this:
public class Transaction
{
public string PersonName { get; set; }
public DateTime TransactionDate { get; set; }
public MoneyCollection TransactedMoney { get; set;}
}
MoneyCollection simply inherits from ObservableCollection<T>, and is a collection of MyMoney type object.
In my GridView, I just want to bind a column to the MoneyCollection's ToString() method. However, binding it directly to the TransactedMoney property makes every entry display the text "(Collection)", and the ToString() method is never called.
Note that I do not want to bind to the items in MoneyCollection, I want to bind directly to the property itself and just call ToString() on it.
I understand that it is binding to the collection's default view. So my question is - how can I make it bind to the collection in such a way that it calls the ToString() method on it?
This is my first WPF project, so I know this might be a bit noobish, but pointers would be very welcome.
You can add property StringRepresentation or something like this in MyMoney class. If you do not want to affect this class, you should write a wrapper - MyMoneyViewModel which will have all needed properties. This is a common way. HIH!
Write a IValueConverter implementation that calls ToString() on the bound collection and returns it and use this converter in the XAML binding expression.
Imagine these two classes:
class Part
{
public string Name { get; set;}
public int Id { get; set; }
}
class MainClass
{
public Part APart { get; set;}
}
How can I bind MainClass to a combo box on a WinForm, so it displays Part.Name (DisplayMember = "Name";) and the selected item of the combo sets the APart property of the MainClass without the need to handle any events on the dropdown.
As far as I know, setting ValueMember of the ComboBox to "Id" means that it will try to set APart to a number (Id) which is not right.
Hope this is clear enough!
What you're looking for is to have the ValueMember (= ComboBox.SelectedItem) be a reference to the object itself, while DisplayMember is a single property of the item, correct? As far as I know, there's no good way to do this without creating your own ComboBox and doing the binding yourself, due to the way ValueMember and DisplayMember work.
But, here's a couple things you can try (assuming you have a collection of Parts somewhere):
Override the `ToString()` method of `Part` to return the `Name` property. Then set your `ComboBox`'s `ValueMember` to `"APart"` and leave `DisplayMember` null. (Untested, so no guarantees)
You can create a new property in Part to return a reference to itself. Set the 'ValueMember' to the new property and 'DisplayMember' to `"Name"`. It may feel like a bit of a hack, but it should work.
Do funny things with your `APart` getter and setter. You'll lose some strong-typing, but if you make `APart` an object and `MainClass` contains the collection of `Part`s, you can set it by `Id` (`int`) or `Part`. (Obviously you'll want to be setting it by Id when you bind the ComboBox to it.)
Part _APart;
object APart
{
get {return _APart;}
set {
if(value is int)
_APart = MyPartCollection.Where(p=>p.Id==value).Single();
else if(value is Part)
_APart = value;
else
throw new ArgumentException("Invalid type for APart");
}
}
If you set the ValueMember of the combo box to null, the databinding will return the selected item (i.e. the Part instance) instead of speciied member. Set the DisplayMember to 'Name'.
I made a little research and found this article where the author has been able to bind to nested properties by extending the standard binding source component.
I've tried it and it seems to work fine.
create a backing class to hold the "information", and create properties for all the data. Then implement System.ComponentModel.INotifyPropertyChanged on that class, something like:
private String _SelectedPart = String.Empty;
public String SelectedPart
{
get
{
return _SelectedPart;
}
set
{
if (_SelectedPart != value)
{
_SelectedPart = value;
// helper method for handing the INotifyPropertyChanged event
PropertyHasChanged();
}
}
}
Then create an "ObjectDataSource" for that class (Shift-Alt-D in VS2008 will bring that up while looking at a form), then click on your ComboBox and set the following properties:
DataSource, set to the ObjectDataSource "BindingSource" you just created.
DisplayMember, Set to the Name propertity of the List of parts
ValueMember, Set to the ID member of the List of parts
DataBindings.SelectedValue, set to the SelectedPart on the "BindingSource" you just created.
I know the above sounds complex, and it might take a bit to find all the parts I just described (wish I could give a tutorial or screenshot), but really it is VERY fast to do once you get used to it.
This is by the way, considered "data-binding" in .NET and there are a few good tutorials out there that can give your more information.