How to get the value from DataGrid's SelectedItem? - silverlight

In my project i have one Datagrid and i bind the following fields that are listed below.
CustomerID, Name, Email.
I have the Entity named WS_Customer. i have put one button control for all row in datagrid.If i click the button means the i need to get the CustomerID value.
How to get it.
If i put like this means,
WS_Customer getid=(WS_Customer)DG.SelectedItem;
getidshows null..
How i got the value?

Assuming you are using MVVM... and you DataGrid is bound to a collection of the WS_Customer objects you can put a property in your view model that you can bind to the SelectedItem property of the DataGrid. Keep in mind the row must be selected for the SelectedItem property to have a value.
In xaml:
<DataGrid SelectedItem="{Binding SelectedWS_Customer}" />
In viewModel:
public WS_Customer SelectedWS_Customer
{
get
{
return _selectedWS_Customer; //private variable
}
set
{
_selectedWS_Customer = value;
}
}

Related

How can the ViewModel request an update in the View in WPF/MVVM?

I have a dependency property on a control in my View that is bound to a field on my ViewModel. When the user clicks a menu item I want the control to update the value of that property so the ViewModel can save it in an XML file. What is the correct mechanism to have the ViewModel request that the View update that property?
Generally with MVVM controls update their bound properties (not fields) immediately as they are edited. The ViewModel is the "state", the View is just one way of seeing that state.
Your control should update the ViewModel whenever it is edited. Your ViewModel can then save it to XML when the menu command is invoked.
I had the problem that the viewmodel was not updated when clicking on a menuitem right after writing in a TextBox.
With the parameter UpdateSourceTrigger=PropertyChanged, it worked for TextBoxes:
<TextBox Grid.Column="5" Grid.Row="7" Text="{Binding SelectedPerson.Room, UpdateSourceTrigger=PropertyChanged}"></TextBox>
But unfortunately not for DatePickers...
The strange thing is that when clicking on a button instead of the menuitem, the DatePicker is updating the viewmodel.
As I don't have more time to look for a bugfix right now, I'll just change my menuitems into buttons.
Edit: the Problem is not the menuitem but the menu itself. When I move the menuitems out of the menu, it works.
Your object must implement INotifyPropertyChanged interface and your properties should look like this
private string _property;
public string Property
{
get { return _property; }
set
{
if(_property == value) return;
_property = value;
RaisePropertyChanged("Property");
}
}
so every change made to the property will be cascaded to view through the binding mechanism.
The menu item command property will be bound to a command declared in the view model and it will trigger a method on view model and set the property value. The change will be cascaded to view:
menuItem.Click -> menuItem.Command.Execute -> viewModel.method -> change the view model property -> raise property changed event -> view property changed through binding

Combo-box loses selection after collection changes

I have a WPF combo box bound to an obvserable collection (OC):
<ComboBox Name="cbCombination" ItemsSource="{Binding Combinations}"
SelectedIndex="0" />
Elsewhere, in the object set as data context:
public ObservableCollection<Combination> Combinations { get; set; }
Combination overrides its ToString and everything is peachy: The combo-box's drop-down displays all Combination items in the Combinations OC. The combo-box's selection box displays the value of the first Combination.
Now, the data-context object has to change the values in its Combinations OC:
var combinationsList = CombinationsManager.CombinationsFor(someParam);
this.Combinations.Clear();
foreach (var combination in combinationsList)
this.Combinations.Add(combination);
NotifyPropertyChanged(#"Combinations");
This causes the combo-box's selection box shows an empty string. (The drop-down is closed. However, when I make it drop down, it does show the correct new Combinations, so it is bound to the updated collection).
I tried to capture both SourceUpdated and (in my dispair) TargetUpdated events (thining of setting the SelectedIndex there), but my event handlers didn't get called!
So my question is: How do I make a WPF ComboBox refresh the value of its selection-box when the observable collection it is bound-to changes?
Update:
I've totally forgotten to mention, and I don't know whether it's important, but the combo-box is within a UserControl. The UserControl's XAML looks like this:
<UserControl x:Class="...CombinationsToolBar"
.... mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ToolBarTray Name="toolBarTray1" >
<ToolBar Name="toolBar1">
<ComboBox Name="cbCombination"
ItemsSource="{Binding Path=Combinations, NotifyOnSourceUpdated=True,
IsAsync=True}"
SelectedIndex="0" IsEditable="False"
SelectionChanged="CbCombinationSelectionChanged"
SourceUpdated="CbCombinationSourceUpdated"
TargetUpdated="CbCombinationTargetUpdated"></ComboBox>
</ToolBar>
</ToolBarTray>
In the UserControl's code I have breakpoints on CbCombinationSelectionChanged, CbCombinationSourceUpdated and CbCombinationTargetUpdated.
The CbCombinationSelectionChanged fires once when the form containing the user control is first loaded. It is indeed called a second time when the Combinations collection is cleared, as #asktomsk said.
The source updated and target updated are not triggered - CbCombinationSourceUpdated and CbCombinationTargetUpdated are not called.
As the combo box is inside a usercontrol and the Combinations collection is within the view model, and as the view model doesn't have access to the combo box, I have no opportunity to set the selected index of the combo unless the events fire.
:(
The problem is in your this.Combinations.Clear();
When you do it, it sets SelectedItem = null and SelectedIndex = -1
So you should set selection again. If you have an access to your ComboBox then just write this cbCombination.SelectedIndex = 0; after filling Combinations list.
Of course you can bind SelectedItem/SelectedIndex to some property in code behind too.
BTW
Also it is not required to call NotifyPropertyChanged(#"Combinations"); after filling the collection because Combinations already implements INotifyPropertyChanged.
Update
To detect that your ObservableCollection was changed, subscribe to CollectionChanged event in your UserControl code behind. Make sure that you subscribed before collection changed!
Combinations.CollectionChanged += (s, e) =>
{
if (cbCombination.Items.Count > 0)
cbCombination.SelectedIndex = 0;
};
Another suggestion
Approach above is works when you do not need a smarter logic than just select zero index in combobox.
But often you will need a more complex logic to select some item. In this case you may add new property to your model:
public Combination SelectedCombination
{
get{ return _selectedCombination; }
set
{
_selectedCombination = value;
NotifyPropertyChanged("SelectedCombination");
}
}
and bind this property to your combobox:
<ComboBox Name="cbCombination" ItemsSource="{Binding Combinations}"
SelectedIndex="0" SelectedItem={Bindings SelectedCombination} />
In this case you can select any item when filling the Combinations collection and it will be automatically selected in combobox:
var combinationsList = CombinationsManager.CombinationsFor(someParam);
this.Combinations.Clear();
foreach (var combination in combinationsList)
this.Combinations.Add(combination);
if (Combinations.Count > 0)
SelectedCombination = Combinations[0];

how to bind autocomplete box to a database table column?

i am currently creating a Gridview using telerik control which displays data from the sql database which i displays through domain datasource used in wcf ria.(ADO.net entity model etc)
i want to add an autocomplete box above my radgrid where i type an name and other matchable entries are also listed.
when i click on the entry then radgrid may display whole row containing that name.
i am using silverlight 4,wcf ria,telerik controls.
please provide a sample coding idea in xaml and xaml.cs.
i tries to access telerik demos but they are not running on my system.
As an example... say you have a list of Customers, of which you want to display their names in your AutoComplete box. Further, your Grid should display all customers, and when a Name is selected in the AutoComplete box, the Selected item of the grid displays.
What you need to do is bind the SelectedItem property of the RadGridView & AutoCompleteBox. What I would do is bind the AutoCompleteBox to a property named SelectedName, like so:
<input:AutoCompleteBox ItemsSource="{Binding Names}" SelectedItem="{Binding SelectedName, Mode=TwoWay}" />
Emphasis on the 'Mode=TwoWay' - this is what will alert your code behind that the UI has changed.
In your code behind, you would create properties like this:
private string selectedName;
public string SelectedName
{
get { return selectedName; }
set
{
if (value != null)
{
var query = (from c in CustomersList
where (c.Name == value)
select c).FirstOrDefault();
SelectedCustomer = (Customer)query;
selectedName = value;
}
}
}
Notice how, when you're setting the SelectedName, you're using LINQ to determine which of the customers were selected. One pitfall here would be if you have multiple names in a list... this code only selects the first. If this is an issue, you probably should rethink your architecture..
Then for your grid, you would bind the SelectedItem like so:
<telerik:RadGridView
....
SelectedItem={Binding SelectedCustomer, Mode=TwoWay"}
....
</telerik:RadGridView>
In your code behind, you'd create this property:
private Customers selectedCustomer;
public Customers SelectedCustomer
{
get { return selectedCustomer; }
set {
selectedCustomer = value;
MyGridView.SelectedItem = selectedCustomer;
}
}
Something like that should get you started.
SS

Difference between SelectedItem, SelectedValue and SelectedValuePath

What is the difference betweeen the following:
SelectedItem
SelectedValue
SelectedValuePath
All these dependency properties are defined in Selector class. I often confuse SelectedItem with SelectedValue , and SelectedValue with SelectedValuePath.
I would like to know the difference between them, and also when do we use them, especially SelectedValue and SelectedValuePath. Please explain their use with some simple examples.
Their names can be a bit confusing :). Here's a summary:
The SelectedItem property returns the entire object that your list is bound to. So say you've bound a list to a collection of Category objects (with each Category object having Name and ID properties). eg. ObservableCollection<Category>. The SelectedItem property will return you the currently selected Category object. For binding purposes however, this is not always what you want, as this only enables you to bind an entire Category object to the property that the list is bound to, not the value of a single property on that Category object (such as its ID property).
Therefore we have the SelectedValuePath property and the SelectedValue property as an alternative means of binding (you use them in conjunction with one another). Let's say you have a Product object, that your view is bound to (with properties for things like ProductName, Weight, etc). Let's also say you have a CategoryID property on that Product object, and you want the user to be able to select a category for the product from a list of categories. You need the ID property of the Category object to be assigned to the CategoryID property on the Product object. This is where the SelectedValuePath and the SelectedValue properties come in. You specify that the ID property on the Category object should be assigned to the property on the Product object that the list is bound to using SelectedValuePath='ID', and then bind the SelectedValue property to the property on the DataContext (ie. the Product).
The example below demonstrates this. We have a ComboBox bound to a list of Categories (via ItemsSource). We're binding the CategoryID property on the Product as the selected value (using the SelectedValue property). We're relating this to the Category's ID property via the SelectedValuePath property. And we're saying only display the Name property in the ComboBox, with the DisplayMemberPath property).
<ComboBox ItemsSource="{Binding Categories}"
SelectedValue="{Binding CategoryID, Mode=TwoWay}"
SelectedValuePath="ID"
DisplayMemberPath="Name" />
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Product
{
public int CategoryID { get; set; }
}
It's a little confusing initially, but hopefully this makes it a bit clearer... :)
Chris
To answer a little more conceptually:
SelectedValuePath defines which property (by its name) of the objects bound to the ListBox's ItemsSource will be used as the item's SelectedValue.
For example, if your ListBox is bound to a collection of Person objects, each of which has Name, Age, and Gender properties, SelectedValuePath=Name will cause the value of the selected Person's Name property to be returned in SelectedValue.
Note that if you override the ListBox's ControlTemplate (or apply a Style) that specifies what property should display, SelectedValuePath cannot be used.
SelectedItem, meanwhile, returns the entire Person object currently selected.
(Here's a further example from MSDN, using TreeView)
Update: As #Joe pointed out, the DisplayMemberPath property is unrelated to the Selected* properties. Its proper description follows:
Note that these values are distinct from DisplayMemberPath (which is defined on ItemsControl, not Selector), but that property has similar behavior to SelectedValuePath: in the absence of a style/template, it identifies which property of the object bound to item should be used as its string representation.
SelectedItem and SelectedValue are an object.
and SelectedValuePath is a string.
for example using the ListBox:
Below listbox1.SelectedValue becomes a string value.
string value = listbox1.SelectedValue;
if you say give me listbox1.SelectedItem it will give you the entire object.
ListItem item = listbox1.SelectedItem;
string value = item.value;
inspired by this question I have written a blog along with the code snippet here. Below are some of the excerpts from the blog
SelectedItem – Selected Item helps to bind the actual value from the DataSource which will be displayed. This is of type object and we can bind any type derived from object type with this property. Since we will be using the MVVM binding for our combo boxes in that case this is the property which we can use to notify VM that item has been selected.
SelectedValue and SelectedValuePath – These are the two most confusing and misinterpreted properties for combobox. But these properties come to rescue when we want to bind our combobox with the value from already created object. Please check my last scenario in the following list to get a brief idea about the properties.
Every control that uses Collections to store data have SelectedValue, SelectedItem property. Examples of these controls are ListBox, Dropdown, RadioButtonList, CheckBoxList.
To be more specific if you literally want to retrieve Text of Selected Item then you can write:
ListBox1.SelectedItem.Text;
Your ListBox1 can also return Text using SelectedValue property if value has set to that before. But above is more effective way to get text.
Now, the value is something that is not visible to user but it is used mostly to store in database. We don't insert Text of ListBox1, however we can insert it also, but we used to insert value of selected item. To get value we can use
ListBox1.SelectedValue
Source

Using MVVM how can I find out if a ComboBox has changed the selected value?

I have a view that has 2 combo boxes (Call them ParentTypeCombo and ChildTypeCombo). Both of these combo boxes have the same backing drop down list (call it WorkItemTypes).
Using MVVM how can I know when the value was changed for these combo boxes? I have bound them to properties (Call them ParentType and ChildType). But as I recall, my setter will not be called by WPF.
I don't want to just go off the event on the combo box because that will go in the code behind, not the View Model.
(I saw an example using an ObservableCollection. But I confess I did not understand it. I used a value called CollectionViewSource that it does not explain what is or where it is obtained.)
Just bind the SelectedItem to a property in the ViewModel for both parent and child
<ComboBox SelectedItem="{Binding ParentSelectedItem}" ... />
// VM
public WorkItemType ParentSelectedItem
{
get { return _parentSelectedItem; }
set
{
if(value != _parentSelectedItem)
{
//HERE you know it has changed value.
_parentSelectedItem = value;
RaisePropertyChanged("ParentSelectedItem");
}
}
}
Also you can have only one collection on the view model and bind them to both combo boxes.
Set the ComboBox IsSyncronyzedWithCurrentItem property to true, than on your vm, call this CollectionViewSource.GetDefualtView([your workitem types]), the return type is ICollectionView or something similar, and it has a current changed event.

Resources