Is there a way to Bind Dictionary to a ListBox?
e.g:
I Have this Class:
class Person
{
private string _firstName;
private string _lastName;
private int _age;
public Person(string firstName, string lastName, int age)
{
this._firstName = firstName;
this._lastName = lastName;
this._age = age;
}
public string FirstName
{
get { return _firstName; }
set { this._firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { this._lastName = value; }
}
public int Age
{
get { return _age; }
set { this._age = value; }
}
}
and I use it as the value of my dictionary:
private Dictionary<string, Person> _persons = new Dictionary<string, Person>();
and i want to Bind it to listBox ... but I need to choose what Item to Bind ...
e.g: I want to Bind Person, then all Person only will appear in DisplayMember of listBox ...
i tried this answer:
stackoverflow.com/questions/854953/datagridview-bound-to-a-dictionary of Chris
but the output displayed on listbox perItem was something like:
{ Key = key, Value = ObjectValue }
Question: Is there another way to do this? or how to fix this atleast edit the item of listbox?
Updated:
I just saw this answer a while ago:
stackoverflow.com/questions/1506987/how-to-bind-dictionary-to-listbox-in-winforms
and it seems working! But my Problem now was How about if I want to Display Data From Values ... what to put on listBox.DisplayMember ?
There isn't a way to specify something like "Person.FirstName" in the DisplayMember of a listbox in winforms.
What you could do is override Person's ToString method or rather than binding a dictionary you could bind a List<Person>...
Or have a class just for binding and the bind List<CustomPerson>.
public class CustomPerson
{
public string Key { get; set; }
public Person Person { get; set; }
public string DisplayValue
{
get { return Person.FirstName; }
}
}
Then set DisplayMember to DisplayValue.
Related
In WPF, I want to create three textboxes for the properties: FullName, FirstName and LastName. The text for these textboxes will be based on the listbox on the left (as shown in the program image below). I'm already done with getting text from the listbox to the textbox but I want to sync the values for the names such that:
changing the value for FullName, changes the listbox, FirstName and LastName box
and changing the value for FirstName and LastName changes the FullName and listbox
Here is what the program looks like:
(Program image)
OK thanks to Jared,I was able to solve the problem by making small changes to his answer but I dont like my solution lol can someone suggest a better revision to this program?
class Student : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return name;
}
set
{
FirstName = value.Split(" ".ToCharArray())?[0];
LastName = value.Split(" ".ToCharArray())?[1];
OnPropertyChanged("Name");
OnPropertyChanged("FirstName");
OnPropertyChanged("LastName");
}
}
private string firstName;
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
name = value + " " + LastName;
OnPropertyChanged("FirstName");
OnPropertyChanged("Name");
}
}
private string lastName;
public string LastName
{
get
{
return lastName;
}
set
{
lastName = value;
name = FirstName + " " + value;
OnPropertyChanged("LastName");
OnPropertyChanged("Name");
}
}
private Course _course;
public Course Course
{
get { return _course; }
set
{
_course = value;
OnPropertyChanged("Course");
}
}
private int _age;
public int Age
{
get { return _age; }
set
{
_age = value;
OnPropertyChanged("Age");
}
}
private DateTime _birthday;
public DateTime Birthday
{
get { return _birthday; }
set
{
_birthday = value;
OnPropertyChanged("Birthday");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I believe what you'll need is a class such as the one below. You'd then bind your listbox to a collection of these, and the form elements to the currently selected item.
I added a space between first and last name. If you want that removed, you'll need to find another way of splitting the first and last names, such as checking capitalization.
Since FullName will be set regardless of which property is modified, I put all the FirePropertyChanged calls in its setter. I haven't tested this, but I assume it will work. :)
EDIT: Changed FullName setter to set the private variable of firstName and lastName instead of the public property.
public class Student : INotifyPropertyChanged
{
public string FullName
{
get
{
return FirstName + " " + LastName;
}
set
{
firstName = value.Split(" ".ToCharArray())?[0];
lastName= value.Split(" ".ToCharArray())?[1];
FirePropertyChanged("FullName");
FirePropertyChanged("FirstName");
FirePropertyChanged("LastName");
}
}
private string firstName;
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
FullName = value + " " + LastName;
}
}
private string lastName;
public string LastName
{
get
{
return firstName;
}
set
{
lastName = value;
FullName = FirstName + " " + value;
}
}
public void FirePropertyChanged (string PropertyName)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
I have two listboxes. One source listbox which is binded to ObservableCollection<Person> MyNetwork The other listbox is my target listbox which is binded to ObservableCollection<Person> Crew.Each time I drop the item in the target listbox I create a new instance of the sourceItem.
Now I would like to update the properties of new istances, but it doesn't seem to work. Is there a way to make the copies of the sourceItems to update when I change one of the sourceItems(FirstName) properties. I'm pretty new to WPF and MVVM and wonder if this is possible or is there a work around to achieve this?
Here what I have so far:
in the ViewModel
Source ListBox:
private ObservableCollection<Person> _myNetwork = new ObservableCollection<Person>();
public ObservableCollection<Person> MyNetwork
{
get { return _myNetwork; }
set { _myNetwork = value; RaisePropertyChanged(); }
}
Target ListBox:
private ObservableCollection<Person> _crew = new ObservableCollection<Person>();
public ObservableCollection<Person> Crew
{
get { return _crew; }
set { _crew = value; RaisePropertyChanged("Crew");}
}
void IDropTarget.Drop(IDropInfo dropInfo)
{
Person sourceItem = dropInfo.Data as Person;
if (dropInfo.Data is Person)
{
Person person = new Person(sourceItem.FirstName,
sourceItem.LastName,
sourceItem.Profession);
Crew.Add(person);
}
}
The Model:
public Person(string FirstName, string LastName, string Profession)
{
_firstName = FirstName;
_lastName = LastName;
_profession = Profession;
}
private string _firstName;
public string FirstName
{
get { return this._firstName; }
set { this._firstName = value; RaisePropertyChanged("FirstName"); }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; RaisePropertyChanged("LastName"); }
}
private string _profession;
public string Profession
{
get { return _profession; }
set { _profession = value; RaisePropertyChanged("Profession"); }
}
I would recommend using a library that wraps the PropertyChanged event so it's easier to update your properties when you need to call them.
Once example is Caliburn for WPF. You can use NotifyOfPropertyChange(() => FirstName) from within your code to update the FirstName property however you need to (it doesn't have to just be used in the setter).
Here is a good article on how to use it.
Example:
using Caliburn.Micro;
namespace CaliburnMicroExample
{
public class ShellViewModel : PropertyChangedBase
{
private string _message;
public string Message
{
get { return _message; }
set
{
_message = value;
NotifyOfPropertyChange(() => Message);
}
}
public ShellViewModel()
{
Message = "Hello World";
}
}
}
I want my custom PropertyGrid with student1 and student2 as nodes with "Name,Section,Percentage,School" as childs for both nodes.
I tried like this :
class StudentClass
{
private string name;
private string section;
private string percentage;
private string school;
[CategoryAttribute("Student1")]
public string School
{
get { return school; }
set { school = value; }
}
[CategoryAttribute("Student1")]
public string Percentage
{
get { return percentage; }
set { percentage = value; }
}
[CategoryAttribute("Student1")]
public string Section
{
get { return section; }
set { section = value; }
}
[CategoryAttribute("Student1")]
public string Name
{
get { return name; }
set { name = value; }
}
private string name1;
[CategoryAttribute("Student2")]
public string Name1
{
get { return name1; }
set { name1 = value; }
}
private string section1;
[CategoryAttribute("Student2")]
public string Section1
{
get { return section1; }
set { section1 = value; }
}
private string percentage1;
[CategoryAttribute("Student2")]
public string Percentage1
{
get { return percentage1; }
set { percentage1 = value; }
}
private string school1;
[CategoryAttribute("Student2")]
public string School1
{
get { return school1; }
set { school1 = value; }
}
}
public Form1()
{
InitializeComponent();
StudentClass sc = new StudentClass();
propertyGrid1.SelectedObject = sc1;
}
The Output is as shown below :
Now in the above picture for Student2 instead of "Name1,Section1,Percentage1,School1" I want to display same as student1.
But I didn't get the required output. So Kindly help me out of this.
I am using C# Winforms in VS2010
And Suggest me how to deny columns resizing i.e., I should not allow user to resize the columns.
You can use the DisplayName attribute:
private string name1;
[CategoryAttribute("Student2"), DisplayName("Name")]
public string Name1
{
get { return name1; }
set { name1 = value; }
}
But note that if the user puts the property grid into A-Z mode, they'll both end up next to each other with no real way to tell them apart. You may find there's a more appropriate way to represent your data.
I am using this Return list in WCF example but I cannot implemment the client code correctly. The example works. I want the list transfered on the client side.
My code so far:
List<Person> aPerson = new List<Person>()
Person y = new Person()'
aPerson.Add(y.id, y.name, y.adress, y.salary, y.country)
This is the server:
[DataContract]
public class Person
{
public string Id;
public string name;
public string address;
public string salary;
public string country;
public Person()
{ }
public Person(string _id, string _name, string _address, string _salary, string _country)
{
Id = _id;
name = _name;
address = _address;
salary = _salary;
country = _country;
}
[DataMember]
public string Idps
{
get { return Id; }
set { Id = value; }
}
[DataMember]
public string nameps
{
get { return name; }
set { name = value; }
}
[DataMember]
public string addressps
{
get { return address; }
set { address = value; }
}
[DataMember]
public string salaryps
{
get { return salary; }
set { salary = value; }
}
[DataMember]
public string countryps
{
get { return country; }
set { country = value; }
}
}
public List <Person> GetData(string Id)
{
//Create a List of Person objects
List<Person>employeelist =new List<Person>();
employeelist.Add(new Person("10", "name", "myAdress", "1000", "myCountry");
}
//Return the list that contains Person objects
return employeelist;
}
I don't know how to implement the client side using the code above. The server returns the list and I want to store the list local at the client.
I think you are best off walking through a full end-to-end example as found here: http://msdn.microsoft.com/en-us/library/bb386386.aspx which should help you get up to speed with WCF.
However, as a jump start... I assume that in your interface you have decorated your method GetData with the [OperationContract] attribute?
Then on the client you need to reference the WCF Service. When adding the service you should click on the Advanced button in the lower-left corner of the dialog. Change the Collection type drop-down from System.Array to
System.Collections.Generic.List.
Finally, your client should be able to call the service with some code like this:
public void SampleClientCode()
{
using (var client = new ServiceReference1.Service1Client())
{
List<Person> results = client.GetData("12345");
// Now do something with the data... Example
string firstPersonsName = results.First().nameps;
}
}
NOTE: Your property naming convention in your Person class is not very good and should be revised.
EDIT: This is a Windows Store (8.1) application
I have a person class as shown below which I am using as a model
public class Person : BaseModel
{
private string _FirstName;
public string FirstName
{
get { return _FirstName; }
set
{
if (_FirstName == value)
return;
_FirstName = value;
RaisePropertyChanged("FirstName");
}
}
private string _MiddleName;
public string MiddleName
{
get { return _MiddleName; }
set
{
if (_MiddleName == value)
return;
_MiddleName = value;
RaisePropertyChanged("MiddleName");
}
}
private string _LastName;
public string LastName
{
get { return _LastName; }
set
{
if (_LastName == value)
return;
_LastName = value;
RaisePropertyChanged("LastName");
}
}
}
where BaseModel is defined as below
using GalaSoft.MvvmLight;
public class BaseModel: ObservableObject
{
}
I am using the Model in a ViewModel class as shown below.
using GalaSoft.MvvmLight;
public class PersonViewModel : ViewModelBase
{
/// <summary>
/// List of searched People
/// </summary>
private ObservableCollection<Person> _People;
public ObservableCollection<Person> People
{
get { return _People; }
set
{
if (_People== value)
return;
_People= value;
RaisePropertyChanged("People");
}
}
}
I am binding the People collection to a GridView as shown below.
<GridView
x:Name="PeopleSearchResultsGridView"
ItemsSource="{Binding People}">
</GridView>
When the search completes I get back a list of people which I add to the list as follows.
var list = await p.SearchPeople();
People = new ObservableCollection<Person>(list);
I see that the setter for the People collection is firing and the RaisePropertyChanged("People") event is also firing however that is not updating the GridView. Can anyone tell me what is wrong here ?