C# WPF Combobox select first item - c#

Goodday,
I want my combobox to select the first item in it. I am using C# and WPF. I read the data from a DataSet. To fill the combobox:
DataTable sitesTable = clGast.SelectAll().Tables[0];
cbGastid.ItemsSource = sitesTable.DefaultView;
Combo box XAML code:
<ComboBox
Name="cbGastid"
ItemsSource="{Binding}"
DisplayMemberPath="Description"
SelectedItem="{Binding Path=id}"
IsSynchronizedWithCurrentItem="True" />
If I try:
cbGastid.SelectedIndex = 0;
It doesn't work.

Update your XAML with this:
<ComboBox
Name="cbGastid"
ItemsSource="{Binding}"
DisplayMemberPath="Description"
SelectedItem="{Binding Path=id}"
IsSynchronizedWithCurrentItem="True"
SelectedIndex="0" /> // Add me!

Try this, instead of SelectedIndex
cbGastid.SelectedItem = sitesTable.DefaultView.[0][0]; // Assuming you have items here.
or set it in Xaml
<ComboBox
Name="cbGastid"
ItemsSource="{Binding}"
DisplayMemberPath="Description"
SelectedItem="{Binding Path=id}"
IsSynchronizedWithCurrentItem="True"
SelectedIndex="0" />

It works for me if I add a SelectedIndex Property in my VM with the proper binding in the xaml. This is in addition to the ItemSource and the SelectedItem. This way SelectedIndex defaults to 0 and I got what I wanted.
public List<string> ItemSource { get; } = new List<string> { "Item1", "Item2", "Item3" };
public int TheSelectedIndex { get; set; }
string _theSelectedItem = null;
public string TheSelectedItem
{
get { return this._theSelectedItem; }
set
{
this._theSelectedItem = value;
this.RaisePropertyChangedEvent("TheSelectedItem");
}
}
And the proper binding in the xaml;
<ComboBox MaxHeight="25" Margin="5,5,5,0"
ItemsSource="{Binding ItemSource}"
SelectedItem="{Binding TheSelectedItem, Mode=TwoWay}"
SelectedIndex="{Binding TheSelectedIndex}" />

Update your XAML with this code :
<ComboBox
Name="cbGastid"
ItemsSource="{Binding}"
DisplayMemberPath="Description"
SelectedItem="{Binding Path=id, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"
IsSynchronizedWithCurrentItem="True" />
Hope it works :)

Try this,
remove from de C# code the following line:
cbGastid.ItemsSource = sitesTable.DefaultView;
and add this:
cbGastid.DataContext = sitesTable.DefaultView

Try this..
int selectedIndex = 0;
cbGastid.SelectedItem = cbGastid.Items.GetItemAt(selectedIndex);
XAML Code:
<ComboBox
Name="cbGastid"
ItemsSource="{Binding}"
DisplayMemberPath="Description"
SelectedItem="{Binding Path=id}"
IsSynchronizedWithCurrentItem="True" />

This works for me... Given an Authors and Books table with a one-to-many relationship. The XAML Looks like this:
<ComboBox DisplayMemberPath="AuthorName" ItemsSource="{Binding Authors}" Name="ComboBoxAuthors"
SelectedItem="{Binding SelectedAuthor}"
IsSynchronizedWithCurrentItem="True" Grid.Row="0" Grid.Column="0"/>
<ComboBox DisplayMemberPath="BookTitle" ItemsSource="{Binding Books}" Name="ComboBoxBooks"
SelectedItem="{Binding SelectedBook}"
IsSynchronizedWithCurrentItem="True" Grid.Row="0" Grid.Column="1" />
Then my ViewModel looks like this:
enter public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
BooksEntities ctx = new BooksEntities();
List<Author> _authors;
List<Book> _books;
Author _selectedAuthor;
Book _selectedBook;
public MainViewModel()
{
FillAuthors();
}
public List<Author> Authors
{
get { return _authors; }
set
{
_authors = value;
NotifyPropertyChanged();
if (_authors.Count > 0) SelectedAuthor = _authors[0]; // <--- DO THIS
}
}
public Author SelectedAuthor
{
get { return _selectedAuthor; }
set
{
_selectedAuthor = value;
FillBooks();
NotifyPropertyChanged();
}
}
public List<Book> Books
{
get { return _books; }
set
{
_books = value;
NotifyPropertyChanged();
if (_books.Count > 0) SelectedBook = _books[0]; // <--- DO THIS
}
}
public Book SelectedBook
{
get { return _selectedBook; }
set
{
_selectedBook = value;
NotifyPropertyChanged();
}
}
#region Private Functions
private void FillAuthors()
{
var q = (from a in ctx.Authors select a).ToList();
this.Authors = q;
}
private void FillBooks()
{
Author author = this.SelectedAuthor;
var q = (from b in ctx.Books
orderby b.BookTitle
where b.AuthorId == author.Id
select b).ToList();
this.Books = q;
}
#endregion
}
Take a look at the Authors and Books properties of the ViewModel class. Once they are set, the usual PropertyChanged event is raised and the SelectedAuthor / SelectedBook is set to the first item.
Hope this helps.

Let me share my solution, that worked for me after several trials.
Here is my combo box:
<ComboBox
Name="fruitComboBox"
ItemsSource="{Binding Fruits}"
SelectedIndex="0"
SelectedValue="{Binding ComboSelectedValue}"
IsSynchronizedWithCurrentItem="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding displayFruitName}"
CommandParameter="{Binding SelectedValue, ElementName=fruitComboBox}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding displayFruitName}"
CommandParameter="{Binding SelectedValue, ElementName=fruitComboBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
In my case, I had to invoke a command every time a new item was selected in the comboBox or when the itemsource was being updated. But, the element at zero index was not getting selected when the item source was updated. So, what did I do? I added:
IsSynchronizedWithCurrentItem="True"
in the comboBox properties. It did the trick for me.
A little code from my ViewModel is below:
/// item source for comboBox
private List<string> fruits = new List<string>();
public List<string> Fruits
{
get { return fruits; }
set
{
fruits = value;
OnPropertyChanged();
ComboSelectedValue = value[0];
}
}
// property to which SelectedValue property of comboxBox is bound.
private string comboselectedValue;
public string ComboSelectedValue
{
get { return comboselectedValue; }
set
{
comboselectedValue = value;
OnPropertyChanged();
}
}
You can refer to this stackoverflow link and msdn link for further clarification regarding IsSynchronizedWithCurrentItem="True"
Hope it Helps! :)

Related

Returning bound checkbox values using MVVM in a WPF form

I have an object that consists of a string and an array. The string populates a ComboBox and the array populates a ListView depending on the selected string value. Each line of the ListViewconsists of a TextBlock and a CheckBox.
On submit I want to be able to verify which items have been selected for further processing but there's a disconnect when using the MVVM approach. I currently have the DataContext of the submit Button binding to the ListView but only the first value is being returned upon submit (somewhere I need to save the selected values to a list I assume but I'm not sure where). I added an IsSelected property to the model which I think is the first step, but after that I've been grasping at straws.
Model
namespace DataBinding_WPF.Model
{
public class ExampleModel { }
public class Example : INotifyPropertyChanged
{
private string _name;
private string[] _ids;
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected != value)
{
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
public string[] IDs
{
get => _ids;
set
{
if (_ids != value)
{
_ids = value;
RaisePropertyChanged("IDs");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(property));
}
}
}
}
ViewModel
namespace DataBinding_WPF.ViewModel
{
public class ExampleViewModel : INotifyPropertyChanged
{
public ObservableCollection<Example> Examples
{
get;
set;
}
// SelectedItem in the ComboBox
// SelectedItem.Ids will be ItemsSource for the ListBox
private Example _selectedItem;
public Example SelectedItem
{
get => _selectedItem;
set
{
_selectedItem = value;
RaisePropertyChanged(nameof(SelectedItem));
}
}
// SelectedId in ListView
private string _selectedId;
public string SelectedId
{
get => _selectedId;
set
{
_selectedId = value;
RaisePropertyChanged(nameof(SelectedId));
}
}
private string _selectedCheckBox;
public string IsSelected
{
get => _selectedCheckBox;
set
{
_selectedCheckBox = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(property));
}
}
public void LoadExample()
{
ObservableCollection<Example> examples = new ObservableCollection<Example>();
examples.Add(new Example { Name = "Mark", IDs = new string[] { "123", "456" }, IsSelected = false });
examples.Add(new Example { Name = "Sally", IDs = new string[] { "789", "101112" }, IsSelected = false });
Examples = examples;
}
/* BELOW IS A SNIPPET I ADDED FROM AN EXAMPLE I FOUND ONLINE BUT NOT SURE IF IT'S NEEDED */
private ObservableCollection<Example> _bindCheckBox;
public ObservableCollection<Example> BindingCheckBox
{
get => _bindCheckBox;
set
{
_bindCheckBox = value;
RaisePropertyChanged("BindingCheckBox");
}
}
}
}
View
<UserControl x:Class = "DataBinding_WPF.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:DataBinding_WPF"
mc:Ignorable = "d"
d:DesignHeight = "300" d:DesignWidth = "300">
<Grid>
<StackPanel HorizontalAlignment = "Left" >
<ComboBox HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding Path=Examples}"
SelectedItem="{Binding SelectedItem}"
DisplayMemberPath="Name"/>
<ListView x:Name="myListView"
ItemsSource="{Binding SelectedItem.IDs}"
DataContext="{Binding DataContext, ElementName=submit_btn}"
SelectedItem="{Binding SelectedId}"
Height="200" Margin="10,50,0,0"
Width="Auto"
VerticalAlignment="Top"
Background="AliceBlue">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox
Name="myCheckBox"
IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=ListViewItem}}"
Margin="5, 0"/>
<TextBlock Text="{Binding}" FontWeight="Bold" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button HorizontalAlignment="Left" Height="20" Width="100"
Click="Submit" x:Name="submit_btn">Submit</Button>
</StackPanel>
</Grid>
</UserControl>
View.cs
namespace DataBinding_WPF.Views
{
/// <summary>
/// Interaction logic for StudentView.xaml
/// </summary>
public partial class StudentView : UserControl
{
public StudentView()
{
InitializeComponent();
}
private void Submit(object sender, EventArgs e)
{
var selectedItems = ((Button)sender).DataContext;
// process each selected item
// foreach (var selected in ....) { }
}
}
}
The ListView control already exposes a selected items collection as property SelectedItems.
private void Submit(object sender, RoutedEventArgs e)
{
var selectedIds = myListView.SelectedItems.Cast<string>().ToList();
// ...do something with the items.
}
However, I doubt that you want to do this in the code-behind, but rather in the view model. For this purpose, WPF offers the concept of commands.
MVVM - Commands, RelayCommands and EventToCommand
What you need is a relay command or delegate command (the name varies across frameworks). It encapsulates a method that should be executed for e.g. a button click and a method to determine whether the command can be executed as an object that can be bound in the view. Unfortunately, WPF does not provide an implementation out-of-the-box, so you either have to copy an implementation like here or use an MVVM framework that already provides one, e.g. Microsoft MVVM Tookit.
You would expose a property Submit of type ICommand in your ExampleViewModel and initialize it in the constructor with an instance of RelayCommand<T> that delegates to a method to execute.
public class ExampleViewModel : INotifyPropertyChanged
{
public ExampleViewModel()
{
Submit = new RelayCommand<IList>(ExecuteSubmit);
}
public RelayCommand<IList> Submit { get; }
// ...other code.
private void ExecuteSubmit(IList selectedItems)
{
// ...do something with the items.
var selectedIds = selectedItems.Cast<string>().ToList();
return;
}
}
In your view, you would remove the Click event handler and bind the Submit property to the Command property of the Button. You can also bind the SelectedItems property of the ListView to the CommandParameter property, so the selected items are passed to the command on execution.
<Button HorizontalAlignment="Left"
Height="20"
Width="100"
x:Name="submit_btn"
Command="{Binding Submit}"
CommandParameter="{Binding SelectedItems, ElementName=myListView}">Submit</Button>
Additionally, a few remarks about your XAML.
Names of controls in XAML should be Pascal-Case, starting with a capital letter.
You should remove the DataContext binding from ListView completely, as it automatically receives the same data context as the Button anyway.
DataContext="{Binding DataContext, ElementName=submit_btn}"
You can save yourself from exposing and binding the SelectedItem property in your ExampleViewModel, by using Master/Detail pattern for hierarchical data.
<Grid>
<StackPanel HorizontalAlignment = "Left" >
<ComboBox HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding Path=Examples}"
IsSynchronizedWithCurrentItem="True"
DisplayMemberPath="Name"/>
<ListView ItemsSource="{Binding Examples/IDs}"
SelectedItem="{Binding SelectedId}"
Height="200" Margin="10,50,0,0"
Width="Auto"
VerticalAlignment="Top"
Background="AliceBlue">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox Name="myCheckBox"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"
Margin="5, 0"/>
<TextBlock Text="{Binding}"
FontWeight="Bold" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button HorizontalAlignment="Left"
Height="20"
Width="100"
Command="{Binding Submit}"
CommandParameter="{Binding SelectedItems, ElementName=myListView}">Submit</Button>
</StackPanel>
</Grid>
If the view's data context is bound to the view then remove the DataContext from the ListView.
You could remove the item template and instead use a GridView like:
<ListView.View>
<GridView >
<GridViewColumn Header="Selected" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
Since the ItemSource is an Observable collection, there are several options to monitor changes in the checkboxes:
Add an event handler to the item changed event of the collection and then you can add the Name or the collection index to a local collection. e.g Examples[e.CollectionIndex].Name
Alternatively iterate over the observable collection and select those Examples where Selected = "true"

How send to combobox 1 property from object

I write this combobox
<ComboBox
x:Name="ComboBoxRole"
SelectedItem="{Binding ApplicationModel.CategoryName}"
ItemsSource="{Binding Categories}"
Style="{StaticResource ComboBoxStyle}" Text="Choose"
/>
for this model
public class CategotyModel : INotifyPropertyChanged, IDataErrorInfo
{
private string id;
private string name;
public string Id
{
get => id;
private set
{
id = value;
NotifyPropertyChanged("Id");
}
}
public string Name
{
get => name;
private set
{
name = value;
NotifyPropertyChanged("Name");
}
}
}
for Item source create this property
public IList<CategotyModel> Categories
{
get
{
var categoriesDTO = _categoryManager.GetAllCategories();
this.categories = mapper.DefaultContext.Mapper.Map<IList<CategotyModel>>(categoriesDTO);
return categories;
}
}
it work fun, but I don't know how sent to combo just 1 parametre , because I take "AppStore.WPF.MVVMLight.Models.CategotyModel" object.
Note: I take the result from server. it's never mind.
(without foreach the IList<CategoryModel> and write to list of the string - i think it's bad way).
Edit
<ComboBox
x:Name="ComboBoxRole"
SelectedItem="{Binding ApplicationModel.CategoryName}"
SelectedValuePath="Name"
DisplayMemberPath="Name"
ItemsSource="{Binding Categories}"
Style="{StaticResource ComboBoxStyle}"
Text="Choose"
/>
You need to fix a few things in your ComboBox: To display the Name properties of the items, add DisplayMemberPath="Name". To select just the name property of the selected item instead of the whole object, add SelectedValuePath="Name", and bind ApplicationModel.CategoryName to SelectedValue instead of SelectedItem.
SelectedItem will still be the whole object, even when SelectedValuePath is in use.
<ComboBox
x:Name="ComboBoxRole"
SelectedValue="{Binding ApplicationModel.CategoryName}"
SelectedValuePath="Name"
DisplayMemberPath="Name"
ItemsSource="{Binding Categories}"
Style="{StaticResource ComboBoxStyle}"
Text="Choose"
/>
you want DisplayMemberPath="Name"
<ComboBox
x:Name="ComboBoxRole"
DisplayMemberPath="Name"
SelectedItem="{Binding ApplicationModel.CategoryName}"
ItemsSource="{Binding Categories}"
Style="{StaticResource ComboBoxStyle}"
Text="Choose"/>

Combobox ItemSource not binding with data from ViewModel

I have a Combobox:
<ComboBox Height="23"
Name="DriveSelection" Width="120"
ItemsSource="{Binding Path=FixedDrives}"
DisplayMemberPath="fixedDrives"
SelectedItem="{Binding Path=DriveSelection_SelectionChanged}"
IsSynchronizedWithCurrentItem="True"/>
Here code for ItemsSource:
private ObservableCollection<DriveInfo> fixedDrives;
public ObservableCollection<DriveInfo> FixedDrives
{
get
{
if(fixedDrives==null)
{
var query =
from driveInfo in DriveInfo.GetDrives()
//where driveInfo.DriveType == DriveType.Fixed
select driveInfo;
fixedDrives= new ObservableCollection<DriveInfo>(query);
return fixedDrives;
}
return fixedDrives;
}
}
and here event handler:
private void DriveSelection_SelectionChanged()
{
if (page.DriveSelection.IsEnabled)
{
this.UpdatePathManager();
}
}
I checked similiar questions like this one or this one and didnt find there any answers.
I know that ViewModel is bounded to View. Other binds to buttons etc are working.
After Updates:
private DriveInfo driveSelection;
public DriveInfo DriveSelection_SelectionChanged
{
get
{
return driveSelection;
}
set
{
if (value == driveSelection) return;
driveSelection = value;
NotifyOfPropertyChange(() => UpdatePathManager()); //UpdatePatchmanager is my function and it exists.
//Notify... throws does not exists in currenct context
}
}
XAML:
<ComboBox Height="23"
Name="DriveSelection"
Width="120"
ItemsSource="{Binding Path=FixedDrives}"
DisplayMemberPath="Name"
SelectedItem="{Binding Path=DriveSelection_SelectionChanged}"
IsSynchronizedWithCurrentItem="True" />
and binding the ViewModel:
public PathSelectionPage()
{
InitializeComponent();
this.DataContext = new PathSelectionPageViewModel(this);
}
After all thouse updates Combobox is still without any options and its greyed out.
And NotifyOfPropertyChange is throwing does not exists in current context
and:
class PathSelectionPageViewModel : ObservableObject, INavigable, INotifyPropertyChanged
Your DisplayMemberPath should be a property name within your DriveInfo class and not DisplayMemberPath="fixedDrives" and SelectedItem should be a property on VM of type DriveInfo not a function
Your DisplayMemberPath Should be a property of your Collection not the Collection Itself.
From this to:
DisplayMemberPath="fixedDrives"
Something Like this:
<ComboBox Height="23"
Name="DriveSelection" Width="120"
ItemsSource="{Binding Path=FixedDrives}"
DisplayMemberPath="Property1"
SelectedItem="Property"
IsSynchronizedWithCurrentItem="True"/>
You don't need write event handler because it is nor MVVM way. You must write something like this
<ComboBox Height="23"
Name="DriveSelection" Width="120"
ItemsSource="{Binding Path=FixedDrives}"
DisplayMemberPath="PropertyOfDriveInfo"
SelectedItem="{Binding Path=SelectedInfo}" />
class ViewModel: INotifyPropertyChanged
{
private ObservableCollection<DriveInfo> fixedDrives;
public ObservableCollection<DriveInfo> FixedDrives
{
get
{
if(fixedDrives==null)
{
var query =
from driveInfo in DriveInfo.GetDrives()
//where driveInfo.DriveType == DriveType.Fixed
select driveInfo;
fixedDrives= new ObservableCollection<DriveInfo>(query);
return fixedDrives;
}
return fixedDrives;
}
}
private DriveInfo _selectedInfo
public DriveInfo SelectedInfo
{
get { return _electedInfo; }
set
{
if (value == _electedInfo) return;
_selectedInfo= value;
NotifyOfPropertyChange(() => SelectedInfo);//must be implemented
}
}
}

Automatically add a combobox when you fill another one

Hi i need to make a program where you have to add an undefined number of elements to a list by choosing them from a combobox. I planned to use 4 basic comboboxes and when the user choose an element from the last one, the program should automatically add another one under the last one (i want to use a stackpanel).
How could i do?
Thanks.
My XAML:
<StackPanel Name="listPanel" Grid.Column="0" Margin="10">
<Label Content="Example" FontWeight="Bold" HorizontalAlignment="Center"/>
<ComboBox Name="ex1Combobox" Margin="0,10,0,0"
ItemsSource="{Binding ExList, Mode=TwoWay}"
SelectedValue="{Binding SelectedEx}"
DisplayMemberPath="Name"
SelectedValuePath="ID"/>
<ComboBox Name="ex2Combobox" Margin="0,10,0,0"
ItemsSource="{Binding ExList, Mode=TwoWay}"
SelectedValue="{Binding SelectedEx}"
DisplayMemberPath="Name"
SelectedValuePath="ID"/>
<ComboBox Name="ex3Combobox" Margin="0,10,0,0"
ItemsSource="{Binding ExList, Mode=TwoWay}"
SelectedValue="{Binding SelectedEx}"
DisplayMemberPath="Name"
SelectedValuePath="ID"/>
</StackPanel>
This is a pretty good example of why you should use MVVM.
Model
Has a collection of selected values only something like
public class MyChoices
{
public IEnumerable<string> Selections {get; set;}
}
ViewModel
Has a collection that extends as soon as you modify the last item
public class MyChoicesViewModel
{
public MyChoicesViewModel()
{
Selections = new ObservableCollection<ChoiceViewModel>();
//Add first empty value
AddNewItem();
Selections.CollectionChanged += (sender, e) =>
{
// If you change the last add another
if (e.NewItems.Contains(Selections.Last()))
AddNewItem();
};
}
public ObservableCollection<ChoiceViewModel> Selections {get; private set;}
public void AddNewItem()
{
var newItem = new ChoiceViewModel();
Selections.Add(newItem);
newItem.PropertyChanged += () =>
{
//This is where we update the model from the ViewModel
Model.Selections = from x in Selections
select x.Value;
}
}
}
public class ChoiceViewModel : INotifyPropertyChanged
{
private string _chosen;
public string Chosen
{
get { return _chosen; }
set {
if (_chosen != value)
{
_chose = value;
OnPropertyChanged();
}
}
}
public void OnPropertyChanged([CallerMemberName] string property)
{
var temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(property));
}
}
}
}
View
<!-- Then show many of them-->
<ListBox ItemsSource="{Binding Selections}"/>

Binding problem with CurrentItem in WPF C#, Can't access "second level data"

I have a problem in c# wpf tring to bind to CurrentItem, i have a list of persons, and each persons can have one of two items. You can select a person in the list and then select it's item in a combobox.
The combobox binds to Persons.CurrentItem.Item and shows what the person have as selected item. But i cant change it, or rather i cant keep the change that is made, it changes back as soon as i select a new person.
The XAML looks like this:
<!--This dose not work-->
<TextBox Height="23" HorizontalAlignment="Left" Margin="148,55,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Persons.CurrentItem.Item.Name}"/>
<!--This works-->
<TextBox Height="23" HorizontalAlignment="Left" Margin="16,306,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text="{Binding Path=Persons.CurrentItem.Name}"/>
<!--This works, we do not bind to CurrentItem-->
<ListBox Height="274" HorizontalAlignment="Left" ItemsSource="{Binding Path=Persons2}" SelectedItem="{Binding Path=SelectedPerson}" Margin="292,26,0,0" Name="listBox2" VerticalAlignment="Top" Width="120" DisplayMemberPath="Name" />
<ComboBox Height="23" HorizontalAlignment="Left" ItemsSource="{Binding Path=Items}" SelectedItem="{Binding Path=SelectedPerson.Item}" Margin="431,26,0,0" Name="comboBox2" VerticalAlignment="Top" Width="120" DisplayMemberPath="Name"/>
</Grid>
As you can see i have added a persons2 with SelectedItem as SelectedPerson. This works fine and i want to mimic it's function but i want to use Current item.
This is the C# code:
// Selectable items
public List<Item> Items { get; set; }
// List of persons, we will bind to it's CurrentItem
public List<Person> Persons { get; set; }
// This works, we do not use CurrentItem
public List<Person> Persons2 { get; set; }
private Person _selectedPerson;
public Person SelectedPerson
{
get { return _selectedPerson; }
set
{
_selectedPerson = value;
NotifyPropertyChanged("SelectedPerson");
}
}
#region Constructo
public Window()
{
InitializeComponent();
DataContext = this;
// Populate Items
Items = new List<Item>
{
new Item {Name = "Hammer"},
new Item {Name = "Axe"}
};
// Populate persons
Persons = new List<Person>() { new Person { Name = "Lisa", Item = Items.FirstOrDefault()}, new Person { Name = "Kauf" } };
Persons2 = new List<Person>(Persons); // make a copy
}
#endregion
#region PropertyChangeHandler
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(name));
}
#endregion
}
public class Item
{
public string Name { get; set; }
}
public class Person
{
public string Name { get; set; }
private Item _item;
public Item Item
{
get { return _item; }
set
{
// We only accass this if we do not bind to CurrentItem
_item = value;
}
}
}
If you test the example you can see that Persons.CurrentItem.Name works, but Persons.CurrentItem.Item.Name dose not, Why? Have i missed something with the level of access?
Is there something i have missed on how to use CurrentItem?
Thanks for enlightening me.
Asked the same question on msdn:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/18eee956-3a91-4db3-a4ff-7e8d127ae301
The solution is not use CurentItem but instead / like this:
<StackPanel>
<ListBox ItemsSource="{Binding Path=Persons}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Name" />
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Path=Items}" SelectedItem="{Binding Persons/Item}" DisplayMemberPath="Name"/>
</StackPanel>

Categories

Resources