Winforms ComboBox DataBinding DisplayMember для свойства SubObject
Я искал 2 часа и более и не могу найти ответ. Поэтому я пробую его здесь:
Я хочу знать, как (и если это вообще можно сделать), я могу привязать список моделей к WinForms ComboBox и использовать свойство свойства модели (в списке) как DisplayMember? См. Здесь код:
public partial class Form1 : Form
{
private List<UserDataModel> userData = new List<UserDataModel>();
public Form1()
{
InitializeComponent();
MyInit();
}
public void MyInit()
{
var userDataModel1 = new UserDataModel();
userDataModel1.Name = "Mike";
userDataModel1.Phone = "555-666";
userDataModel1.Home = new HomeDataModel();
userDataModel1.Home.StreetName = "MikeStreet";
userDataModel1.Home.GeoLocationX = 111;
userDataModel1.Home.GeoLocationY = 222;
var userDataModel2 = new UserDataModel();
userDataModel2.Name = "Jonathan";
userDataModel2.Phone = "777-888";
userDataModel2.Home = new HomeDataModel();
userDataModel2.Home.StreetName = "JonathanStreet";
userDataModel2.Home.GeoLocationX = 333;
userDataModel2.Home.GeoLocationY = 444;
userData.Add(userDataModel1);
userData.Add(userDataModel2);
// This works as usually:
/*
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Home";
comboBox1.DataSource = userData;
*/
// But this works not (either with comboBox1.DataBindings.Add() nor with BindingSource):
comboBox1.DisplayMember = "Home.StreetName";
comboBox1.ValueMember = "Home";
comboBox1.DataSource = userData;
// To drive me crazy, THAT shit works:
textBox1.DataBindings.Add("Text", userData, "Home.StreetName");
/*
So how can i use a String-Property of a SubObject as ComboBox-DisplayMember ???
BTW: To rebuild the sample, you only need a normal Forms Application and
then drop a ComboBox and a TextBox on it. Copy that code here, and run it.
*/
}
}
internal sealed class UserDataModel
{
public string Name { get; set; }
public string Phone { get; set; }
public HomeDataModel Home { get; set; }
}
internal sealed class HomeDataModel
{
public string StreetName { get; set; }
public int GeoLocationX { get; set; }
public int GeoLocationY { get; set; }
}
Ответы
Ответ 1
Просто добавлен в ваш код один метод (событие на самом деле), и он работает.
public partial class Form1 : Form
{
private List<UserDataModel> userData = new List<UserDataModel>();
public Form1()
{
InitializeComponent();
MyInit();
}
public void MyInit()
{
var userDataModel1 = new UserDataModel();
userDataModel1.Name = "Mike";
userDataModel1.Phone = "555-666";
userDataModel1.Home = new HomeDataModel();
userDataModel1.Home.StreetName = "MikeStreet";
userDataModel1.Home.GeoLocationX = 111;
userDataModel1.Home.GeoLocationY = 222;
var userDataModel2 = new UserDataModel();
userDataModel2.Name = "Jonathan";
userDataModel2.Phone = "777-888";
userDataModel2.Home = new HomeDataModel();
userDataModel2.Home.StreetName = "JonathanStreet";
userDataModel2.Home.GeoLocationX = 333;
userDataModel2.Home.GeoLocationY = 444;
userData.Add(userDataModel1);
userData.Add(userDataModel2);
// This works as usually:
/*
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Home";
comboBox1.DataSource = userData;
*/
// But this works not (either with comboBox1.DataBindings.Add() nor with BindingSource):
comboBox1.DisplayMember = "Home.StreetName";
comboBox1.ValueMember = "Home";
comboBox1.DataSource = userData;
// To drive me crazy, THAT shit works:
textBox1.DataBindings.Add("Text", userData, "Home.StreetName");
/*
So how can i use a String-Property of a SubObject as ComboBox-DisplayMember ???
BTW: To rebuild the sample, you only need a normal Forms Application and
then drop a ComboBox and a TextBox on it. Copy that code here, and run it.
*/
}
// To add this method - follow to my instructions below
private void ComboBoxFormat(object sender, ListControlConvertEventArgs e)
{
e.Value = ((UserDataModel)e.ListItem).Home.StreetName;
}
}
internal sealed class UserDataModel
{
public string Name { get; set; }
public string Phone { get; set; }
public HomeDataModel Home { get; set; }
}
internal sealed class HomeDataModel
{
public string StreetName { get; set; }
public int GeoLocationX { get; set; }
public int GeoLocationY { get; set; }
}
Чтобы создать этот метод (событие), перейдите в форму в режиме [Дизайн], щелкните правой кнопкой мыши на ComboBox → Свойства.
В верхней части окна "Свойства" нажмите "События" (значок молнии),
найдите формат в списке событий ниже (в разделе "Свойство изменено" ) и введите там какое-либо имя события, скажем: ComboBoxFormat и нажмите Enter.
Что это;)
Ответ 2
Здесь есть аналогичный вопрос. В отмеченном ответе вы можете видеть, что они устанавливают BindingContext
для Form
на ComboBox
и, похоже, работают для них...
//...
comboBox1.BindingContext = this.BindingContext;
Надеюсь, что это поможет...
Ответ 3
Хорошо, у меня работает DisplayMember. Вы не можете использовать "Главная" как ValueMember как свой объект, вам нужно указать на один из его свойств (StreetName, GeoLocationX, GeoLocationY).
public partial class Form1 : Form
{
private List<UserDataModel> userData = new List<UserDataModel>();
public Form1()
{
InitializeComponent();
MyInit();
}
public void MyInit()
{
var mymodel = new UserDataModel("Derek", "999-999", new HomeDataModel("Sesame Street", 111, 222));
var mymodel1 = new UserDataModel("John", "999-999", new HomeDataModel("Tin Can Alley", 333, 444));
userData.Add(mymodel);
userData.Add(mymodel1);
BindingSource bs = new BindingSource();
bs.DataSource = userData;
comboBox1.DataSource = bs;
comboBox1.DisplayMember = "Home.StreetName";
}
}
internal sealed class UserDataModel
{
public string Name { get; set; }
public string Phone { get; set; }
public HomeDataModel Home { get; set; }
public UserDataModel()
{
}
public UserDataModel(string name, string phone, HomeDataModel home)
{
this.Name = name;
this.Phone = phone;
this.Home = home;
}
}
internal sealed class HomeDataModel
{
public string StreetName { get; set; }
public int GeoLocationX { get; set; }
public int GeoLocationY { get; set; }
public HomeDataModel()
{
}
public HomeDataModel(string streetname, int x, int y)
{
this.StreetName = streetname;
this.GeoLocationX = x;
this.GeoLocationY = y;
}
}
Ответ 4
Чтобы уточнить: ComboBox использует всегда хостинговые формы BindingContext по умолчанию. Я тестировал его с помощью этого кода:
var bc = comboBox1.BindingContext;
if (bc == this.BindingContext)
{
if (bc.Equals(this.BindingContext))
{
MessageBox.Show("combobox always use same binding context as his hosting form");
}
}
и отобразилось окно сообщения.