I have one Listbox and applied one DataTemplate like this
<ListBox>
<ListBox.ItemTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Grid.Row=0/>
<ComoboBox Name="test"
DisplayMemberPath="Country"
SelectedValuePath="Country_ID">
</Grid>
How will I load ItemSource to this ComboBox dynamically based on each item selected in the ListBox? Iam new to WPF... pls help with your valuable suggestions.
<ListBox>
<ListBox.ItemTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Grid.Row=0/>
<ComoboBox Name="test"
DataContent="{Binding RelativeSource={RelativeSource AncestorType=ListBox}}"
ItemsSource="{Binding}"
DisplayMemberPath="Country"
SelectedValuePath="Country_ID">
</Grid>
Now your combocbox is always have the same itemssource as the parent listbox.
One way to do this is to bind the ItemsSource of your ComboBox to the SelectedValue property of the ListBox. For this to work the ListBox needs to be bound to a collection of items that contains a list of items that the ComboBox will bind to.
<ListBox
x:Name="CategoryList"
ItemsSource="{Binding Path=MasterList,
RelativeSource={RelativeSource AncestorType=Window}}"
DisplayMemberPath="MasterProperty"
SelectedValuePath="Details"
/>
<ComboBox
ItemsSource="{Binding Path=SelectedValue, ElementName=CategoryList}"
DisplayMemberPath="DetailProperty"
Grid.Row="1"
/>
In this example I have created a public property in the code behind of the window that exposes a list of objects containing the Details collection.
public List<Master> MasterList { get; set; }
public class Master
{
public string MasterProperty { get; set; }
public List<Detail> Details { get; set; }
}
public class Detail
{
public string DetailProperty { get; set; }
}
Related
This is the custom object:
public class FileItem
{
public string Name { get; set; }
public string Path { get; set; }
}
Collection:
public ObservableCollection<FileItem> collection { get; set; }
Combobox:
<ComboBox
Name="cbCollection"
ItemsSource="{Binding interfaces}"/>
ListBox:
<ListBox
Name="lbCollection "
ItemsSource="{Binding collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So my Combobox is populated with my object collection and i want to see all its properties in my ListBox.
Currently:
I can see only the property Name.
i can see all the objects from my Combobox and not only the selected one.
If you want to see more than just the name property, you'll need to extend the data template to include the additional properties.
If you want to see the selected item's properties, then you should bind to the combo box's SelectedItem property. Actually I don't think you want a ListBox as there is only one selected item.
This should get you started:
<ContentControl Content="{Binding ElementName=cbCollection, Path=SelectedItem}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:FileItem}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
I am farily new to mvvm so bear with me. I have 2 View models which are inherited namely DBViewModel and PersonViewModel. i would like to add the person object in DBViewModel and bind 2 combobox with observablecollection in PersonViewModel.
public class PersonViewModel
{
private ICommand AddCommand ;
public Person PersonI{get;set;}
public ObservableCollection<Person> EmployeeList{ get; set; }
public ObservableCollection<String> OccupationList{ get; set; }
public PersonViewModel()
{
PersonI = new Person();
this.AddCommand = new DelegateCommand(this.Add);
// get OccupationList and EmployeeList
}
......
}
public class DBViewModel : PersonViewModel
{
public PersonViewModel PersonVM { get; set; }
public PersonViewModel()
{
PersonVM = new PersonViewModel();
}
....
}
<DataTemplate DataType='{x:Type viewModel:DBViewModel}'>
<StackPanel>
<TextBox Text="{Binding PersonI.Name}" />
<ComboBox Name="cboccupation" ItemsSource="{Binding OccupationList}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedItem}" SelectedValuePath="Id"/>
<Button Content="Add" Command="{Binding AddCommand}" />
<DataGrid ItemsSource="{Binding EmployeeList}" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Occupation">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding OccupationList}"
DisplayMemberPath="Name" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</DataTemplate>
if you want an easier approach I'm thinking you could set a datastore field using blend and bind both controls to that field.
Your bindings are trying to bind to the properties PersonI and OccupationList on the DBViewModel, however those properties do not exist.
You need to point them to the PersonVM.PersonI and PersonVM.OccupationList instead.
<TextBox Text="{Binding PersonVM.PersonI.Name}" />
<ComboBox ItemsSource="{Binding PersonVM.OccupationList}" ... />
For your ComboBox binding inside the DataGrid, that probably will not work because the DataContext of each row in the Grid is a Person object (specified by the DataGrid.ItemsSource), and I don't think Person has a property called OccupationList.
You need to change the Source of your binding to use the object that has the OccupationList property.
For example, if your DataGrid was named MyDataGrid, the following binding for that ComboBox would work
<ComboBox ItemsSource="{Binding
ElementName=MyDataGrid,
Path=DataContext.PersonVM.OccupationList}" ... />
Alternatively, you could use a RelativeSource binding to have it look for the parent DataGrid object without needing to specify a name
<ComboBox ItemsSource="{Binding
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},
Path=DataContext.PersonVM.OccupationList}" ... />
As a side note, you seem to be a bit confused about bindings and the DataContext. I like to blog about beginner WPF topics, and would recommend reading What is this "DataContext" you speak of?. I find it has helped many WPF beginners on this site understand the basic binding concept. :)
I'm attempting to learn WPF and MVVM at the same time, and need some help with a binding. I'm still trying to get my head wrapped around binding controls to properties of a class.
Here is my Malfunctions ViewModel:
public class Malfunctions : ViewModelBase {
public ObservableCollection<Model.PartMalfunction> AllPartMalfunctions {
get;
private set;
}
public ObservableCollection<Model.Part> AllParts {
get;
private set;
}
}
Here is the Model.PartMalfunction.cs:
public class PartMalfunction{
public ObservableCollection<Model.PartSerial> AllPartSerials {
get;
set;
}
}
Here is the Model.Part.cs:
public class Part {
public string Label { get; set; }
public string Value { get; set; }
}
I have a DataGrid that binds to the AllPartMalfunctions ObservableCollection in the Malfunctions ViewModel. This binding is working just great.
I have another DataGrid nested in the RowDetailsTemplate, and it is binding to AllPartSerials in the PartMalfunction model. This binding is working just fine as well.
My problem is with a combobox that is inside of the nested DataGrid. I want to bind this combobox to the AllParts ObservableCollection in the Malfunctions ViewModel. How do I do this?
<DataGrid ItemsSource="{Binding AllPartMalfunctions}" AutoGenerateColumns="False" Width="Auto"
RowDetailsVisibilityMode="Visible">
<DataGrid.Columns>
<!--removed for brevity-->
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding AllPartSerials }" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="cboPart" VerticalAlignment="Center" ItemsSource="{Binding AllParts}" DisplayMemberPath="Label" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
A similar approach has been stuck in my case. I realized one with a different view model structure.
public class PartMalfunction{
public ObservableCollection<Model.PartSerial> AllPartSerials {
get;
set;
}
public ObservableCollection<Model.Part> AllParts {
get { return SomeStaticClass.AllParts; }
}
}
Binding naturally worked even in DataTemplate. Hope this fits to your domain.
Give the element that binds to Malfunctions a Name and bind using a relative path, like shown below in the line containing the ComboBox. I assume for my example that a StackPanel contains the DataGrid and the StackPanel is bound to a Malfunctions property of the container's view model.
<StackPanel x:Name="MalfunctionsGrid" DataContext={Binding Malfunctions}" Orientation="Vertical">
...
<DataGrid ItemsSource="{Binding AllPartMalfunctions}" AutoGenerateColumns="False" Width="Auto"
RowDetailsVisibilityMode="Visible">
...
...
<ComboBox Name="cboPart" VerticalAlignment="Center" ItemsSource="{Binding Path=DataContext.AllParts, ElementName=MalfunctionsGrid}" DisplayMemberPath="Label" />
...
...
Here is my situation:
<ListBox ItemsSource="{Binding Path=AvailableUsers}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Id}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Command="{Binding Path=Load}" CommandParameter={???? What goes here ????}/>
What I want is to pass the Id that is currently selected in the ListBox. I have a viewmodel behind the scenes that essentially looks like this:
public class ViewModel : DependencyObject
{
ICommand Load { get; set; }
// dependency property but I didn't bother to write it out like one
List<User> AvailableUsers { get; set}
}
How can I send the currently selected item using the xaml?
Try this:
Name your listbox
Update the CommandParameter to:
CommandParameter="{Binding ElementName=listBox1,Path=SelectedItem}"
I have the following class:
public class UserGroup
{
public string GroupName { get; set; }
public bool IsIntheGroup{ get; set; }
}
I want to bind an ObservableCollection of UserGroup items to listbox containing checkbox’s for each item in the collection and the checkbox is cheked based on the IsIntheGroup property of the UserGroup. In my ViewModel I made an ObservableCollection of the UserGroup class:
public ObservableCollection<UserGroup> Groups { get; set; }
and loaded its contents (instances of UserGroup) from my database model
I used the following code in my view:
<ListBox ItemsSource="{Binding Groups, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsIntheGroup, Mode=TwoWay}"/>
<TextBlock Text="{Binding GroupName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem is I am not notified when the user checks/unchecks a check box in the list so my two way binding failed…
How do I do a two way binding in such a case?
Your UserGroup class should implement INotifyPropertyChanged, and each property of that class should invoke the PropertyChanged event in their setters. ObservableCollection will only notify the UI of additions of removals from the collection, and not property changes of each individual instance in the collection.