Снова о привязке данных к ComboBox.
От:
Сергей
Дата: 24.03.09 08:44
Оценка:
Добрый день!
Такой вопрос:
Есть ComboBox.
Есть объект класса, со свойством idType, и типизированным листом в котором хранятся
варианты idType(id, sTitle).
Хочется, чтобы ComboBox был заполнен элементами из типизированного листа
, и при этом позиционировался на элементе с id=idType и записывал
выбранное значение в idType.
cbJobType.DataSource = oJob.loTypes;
cbJobType.DisplayMember = "Title" ;
cbJobType.ValueMember = "Id" ;
cbJobType.SelectedValue = oJob.idType;
bndg = new Binding("ValueMember" , oJob, "idType" );
cbJobType.DataBindings.Add(bndg);
при таком написании — "слетает" Binding с других объектов
Binding bndg = new Binding("Text" , oJob, "ID" );
lblID.DataBindings.Add(bndg);
bndg = new Binding("Text" , oJob, "sLink" );
lblLink.DataBindings.Add(bndg);
bndg = new Binding("Text" , oJob, "sStatus" );
lblStatus.DataBindings.Add(bndg);
cbJobType.DataSource = oJob.loTypes;
cbJobType.DisplayMember = "Title" ;
cbJobType.ValueMember = "Id" ;
cbJobType.SelectedValue = oJob.idType;
bndg = new Binding("ValueMember" , oJob, "idType" );
cbJobType.DataBindings.Add(bndg);
Спасибо.
Re: Снова о привязке данных к ComboBox.
От:
solder
Дата: 25.03.09 10:20
Оценка:
Здравствуйте, Сергей.
Не уверен, что всё понял.
Но может вам пригодится мой опыт.
Мне не оч. нравится работа combobox-а, много чем долго писать.
Я его запихал в свой MyComboBox : UserControl.
Он там представлен как член данных:_cb.
Теперь к этому контролу можно биндить массив любых объектов в качестве DataSource и этого же типа оъект к SelectedItem.
_cb1.DataBindings.Add("DataSource" , data, "Source" , false , DataSourceUpdateMode.OnPropertyChanged);
_cb1.DataBindings.Add("SelectedItem" , data, "Item" , false , DataSourceUpdateMode.OnPropertyChanged);
На 100% правильность не претендую.
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace HBscheduler
{
public partial class MyComboBox : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MyComboBox()
{
InitializeComponent();
_cb.SelectedIndexChanged += SelectedIndexChanged;
}
private void SelectedIndexChanged(object sender, EventArgs e)
{
if (_cb.SelectedIndex != _SelectedIndex)
{
SelectedItem = _data.GetValue(_cb.SelectedIndex);
}
}
private Array _data = new object [0];
public Array DataSource
{
get
{
return _data;
}
set
{
if (value != null && value .Length != 0 && value != _data)
{
if (CompareArrays(_data, value )) return ;
//remember current item name
Object current_item = null ;
if (_data != null && _SelectedIndex >= 0 && _SelectedIndex < _data.Length)
{
current_item = _data.GetValue(_SelectedIndex);
}
_data = value ;
//change combobox item list
_cb.SelectedIndexChanged -= SelectedIndexChanged;
_cb.DataSource = GetStrings(_data);
_cb.SelectedIndexChanged += SelectedIndexChanged;
//find the same item in combo box
int SelectedIndex = _data.Length > 0 ? 0: - 1;
if (current_item != null )
{
for (int i = 0; i < _data.Length; i++)
{
if (_data.GetValue(i).Equals(current_item))
{
SelectedIndex = i;
break ;
}
}
}
_cb.SelectedIndex = _SelectedIndex = SelectedIndex;
if (PropertyChanged != null )
{
PropertyChanged(this , new PropertyChangedEventArgs("SelectedItem" ));
}
}
}
}
private int _SelectedIndex = -1; // should be sihronised to _cb.SelectedIndex
public Object SelectedItem
{
get
{
{
if (_SelectedIndex >= 0 && _SelectedIndex < _data.Length)
{
return _data.GetValue(_SelectedIndex);
}
return null ;
}
}
set
{
if (value != null && !value .Equals(SelectedItem))
{
int SelectedIndex = _data.Length > 0 ? 0 : -1;
for (int i = 0; i < _data.Length; i++)
{
if (_data.GetValue(i).Equals(value ))
{
SelectedIndex = i;
break ;
}
}
if (_SelectedIndex != SelectedIndex)
{
_cb.SelectedIndex = _SelectedIndex = SelectedIndex;
if (PropertyChanged != null )
{
PropertyChanged(this , new PropertyChangedEventArgs("SelectedItem" ));
}
}
}
}
}
private static string [] GetStrings(Array ar)
{
string [] s = new string [ar.Length];
for (int i = 0; i < ar.Length; i++)
{
object o = ar.GetValue(i);
s[i] = string .Empty;
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(o))
{
if (property .Name.Equals("Name" ))
{
string str = property .GetValue(o) as string ;
if (str != null )
{
s[i] = str;
}
break ;
}
}
if (s[i].Length == 0)
{
s[i] = o.ToString();
}
}
return s;
}
private static bool CompareArrays(Array ar1, Array ar2)
{
if (ar1 == null && ar2 == null ) return true ;
if (ar1 == null ) return false ;
if (ar2 == null ) return false ;
if (ar1.Length != ar2.Length) return false ;
for (int i = 0; i < ar1.Length; i++)
{
object o1 = ar1.GetValue(i);
object o2 = ar2.GetValue(i);
if (o1 == null && o2 == null ) continue ;
if (o1 == null ) return false ;
if (o2 == null ) return false ;
if (!o1.Equals(o2)) return false ;
}
return true ;
}
}
}
Re[2]: Снова о привязке данных к ComboBox.
От:
Сергей
Дата: 25.03.09 10:43
Оценка:
Здравствуйте, solder:
Приведите пример объявления _cb и InitializeComponent (для MyComboBox)
Сергей.
Re[3]: Снова о привязке данных к ComboBox.
От:
solder
Дата: 25.03.09 11:02
Оценка:
partial class MyComboBox
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null ;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null ))
{
components.Dispose();
}
base .Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this ._cb = new System.Windows.Forms.ComboBox();
this .SuspendLayout();
//
// _cb
//
this ._cb.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this ._cb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this ._cb.FormattingEnabled = true ;
this ._cb.Location = new System.Drawing.Point(0, 0);
this ._cb.Margin = new System.Windows.Forms.Padding(0);
this ._cb.Name = "_cb" ;
this ._cb.Size = new System.Drawing.Size(157, 21);
this ._cb.TabIndex = 0;
//
// MyComboBox
//
this .AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this .AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this .Controls.Add(this ._cb);
this .Name = "MyComboBox" ;
this .Size = new System.Drawing.Size(157, 21);
this .ResumeLayout(false );
}
#endregion
private System.Windows.Forms.ComboBox _cb;
}
Re[4]: Снова о привязке данных к ComboBox.
От:
Сергей
Дата: 25.03.09 11:42
Оценка:
Не работает. может я не то что-то делаю?
Падает с ошибкой: "cast array.Int32 to array.object"
вот пример кода:
bndg = new Binding("DataSource" , oJob.loTypes, "Id" , false , DataSourceUpdateMode.OnPropertyChanged);
cbJobType_test.DataBindings.Add(bndg);
bndg = new Binding("SelectedItem" , oJob.cbidType, "Id" , false , DataSourceUpdateMode.OnPropertyChanged);
cbJobType_test.DataBindings.Add(bndg);
loTypes — это
List<Combo> loTypes = new List<Combo>();;
oJob.cbidType — это объект класса Combo
Combo — это:
class Combo
{
private Int32 id;
public Int32 Id
{
get { return this .id; }
set { this .id = value ; }
}
private Int32 idadditional1;
public Int32 idAdditional1
{
get { return this .idadditional1; }
set { this .idadditional1 = value ; }
}
private Int32 idadditional2;
public Int32 idAdditional2
{
get { return this .idadditional2; }
set { this .idadditional2 = value ; }
}
private Int32 idadditional3;
public Int32 idAdditional3
{
get { return this .idadditional3; }
set { this .idadditional3 = value ; }
}
private string sTitle;
public string Title
{
get { return this .sTitle; }
set { this .sTitle = value ; }
}
public Combo()
{
}
}
Re[5]: Снова о привязке данных к ComboBox.
От:
solder
Дата: 25.03.09 13:13
Оценка:
С листом в качестве соуса не пробовал.
Пробовал только с массивом.
Счас попробую, скорее всего небольшая переделка требуется.
Попробую подкорректировать.
Re[6]: Снова о привязке данных к ComboBox.
От:
solder
Дата: 25.03.09 14:04
Оценка:
тоже самое только теперь в качестве DataSource может быть любой IEnumerable
проверил с листом и массивом.
public partial class MyComboBox : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MyComboBox()
{
InitializeComponent();
_cb.SelectedIndexChanged += SelectedIndexChanged;
}
private void SelectedIndexChanged(object sender, EventArgs e)
{
if (_cb.SelectedIndex != _SelectedIndex)
{
SelectedItem = _data.GetValue(_cb.SelectedIndex);
}
}
private object [] _data = new object [0];
public object DataSource
{
get
{
return _data;
}
set
{
if (value == null ) return ;
IEnumerable en = value as IEnumerable;
if (en == null ) return ;
object [] val = en.Cast<object >().ToArray();
if (val.Length != 0 && value != _data)
{
if (CompareArrays(_data, val)) return ;
//remember current item name
Object current_item = null ;
if (_data != null && _SelectedIndex >= 0 && _SelectedIndex < _data.Length)
{
current_item = _data.GetValue(_SelectedIndex);
}
_data = val;
//change combobox item list
_cb.SelectedIndexChanged -= SelectedIndexChanged;
_cb.DataSource = GetNames(_data);
_cb.SelectedIndexChanged += SelectedIndexChanged;
//find the same item in combo box
int SelectedIndex = _data.Length > 0 ? 0: - 1;
if (current_item != null )
{
for (int i = 0; i < _data.Length; i++)
{
if (_data.GetValue(i).Equals(current_item))
{
SelectedIndex = i;
break ;
}
}
}
_cb.SelectedIndex = _SelectedIndex = SelectedIndex;
if (PropertyChanged != null )
{
PropertyChanged(this , new PropertyChangedEventArgs("SelectedItem" ));
}
}
}
}
private int _SelectedIndex = -1; // should be sihronised to _cb.SelectedIndex
public Object SelectedItem
{
get
{
{
if (_SelectedIndex >= 0 && _SelectedIndex < _data.Length)
{
return _data.GetValue(_SelectedIndex);
}
return null ;
}
}
set
{
if (value != null && !value .Equals(SelectedItem))
{
int SelectedIndex = _data.Length > 0 ? 0 : -1;
for (int i = 0; i < _data.Length; i++)
{
if (_data.GetValue(i).Equals(value ))
{
SelectedIndex = i;
break ;
}
}
if (_SelectedIndex != SelectedIndex)
{
_cb.SelectedIndex = _SelectedIndex = SelectedIndex;
if (PropertyChanged != null )
{
PropertyChanged(this , new PropertyChangedEventArgs("SelectedItem" ));
}
}
}
}
}
private static bool CompareArrays(Array ar1, Array ar2)
{
if (ar1 == null && ar2 == null ) return true ;
if (ar1 == null ) return false ;
if (ar2 == null ) return false ;
if (ar1.Length != ar2.Length) return false ;
for (int i = 0; i < ar1.Length; i++)
{
object o1 = ar1.GetValue(i);
object o2 = ar2.GetValue(i);
if (o1 == null && o2 == null ) continue ;
if (o1 == null ) return false ;
if (o2 == null ) return false ;
if (!o1.Equals(o2)) return false ;
}
return true ;
}
private static string [] GetNames(Array ar)
{
string [] s = new string [ar.Length];
for (int i = 0; i < ar.Length; i++)
{
object o = ar.GetValue(i);
s[i] = string .Empty;
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(o))
{
if (property .Name.Equals("Name" ))
{
string str = property .GetValue(o) as string ;
if (str != null )
{
s[i] = str;
}
break ;
}
}
if (s[i].Length == 0)
{
s[i] = o.ToString();
}
}
return s;
}
Re[5]: Снова о привязке данных к ComboBox.
От:
Сергей
Дата: 25.03.09 14:22
Оценка:
Не компилируется класс:
Error 2 Using the generic type 'System.Collections.Generic.IEnumerable<T>' requires '1' type arguments S:\TEMP\WindowsApplication1\WindowsApplication1\MyComboBox.cs 102 5 WindowsApplication1
IEnumerable en = value as IEnumerable;
Re[6]: Снова о привязке данных к ComboBox.
От:
Аноним
Дата: 26.03.09 07:16
Оценка:
Здравствуйте, Сергей, Вы писали:
С>Не компилируется класс:
С>Error 2 Using the generic type 'System.Collections.Generic.IEnumerable<T>' requires '1' type arguments
Надо поменять
using System.Collections.Generic;
на
using System.Collections;
и ещё я кусочек поправил
private object [] _data = new object [0];
private object _common_data;
public object DataSource
{
get
{
return _common_data;
}
set
{
if (value != null )
{
IEnumerable en = value as IEnumerable;
if (en != null )
{
object [] val = en.Cast<object >().ToArray();
if (val.Length != 0 && !CompareArrays(_data, val))
{
//remember current item name
Object current_item = null ;
if (_data != null && _SelectedIndex >= 0 && _SelectedIndex < _data.Length)
{
current_item = _data.GetValue(_SelectedIndex);
}
_common_data = value ;
_data = val;
//change combobox item list
_cb.SelectedIndexChanged -= SelectedIndexChanged;
_cb.DataSource = GetNames(_data);
_cb.SelectedIndexChanged += SelectedIndexChanged;
//find the same item in combo box
int SelectedIndex = _data.Length > 0 ? 0 : -1;
if (current_item != null )
{
for (int i = 0; i < _data.Length; i++)
{
if (_data.GetValue(i).Equals(current_item))
{
SelectedIndex = i;
break ;
}
}
}
_cb.SelectedIndex = _SelectedIndex = SelectedIndex;
if (PropertyChanged != null )
{
PropertyChanged(this , new PropertyChangedEventArgs("SelectedItem" ));
}
}
}
}
}
}
Re[7]: Снова о привязке данных к ComboBox.
От:
Сергей
Дата: 26.03.09 07:31
Оценка:
object [] val = en.Cast<object >().ToArray();
Error 'System.Collections.IEnumerable' does not contain a definition for 'Cast'
Re[8]: Снова о привязке данных к ComboBox.
От:
Аноним
Дата: 26.03.09 08:04
Оценка:
Здравствуйте, Сергей, Вы писали:
С>object [] val = en.Cast<object >().ToArray();
С>Error 'System.Collections.IEnumerable' does not contain a definition for 'Cast'
Вот весь заголовок
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
Re[9]: Снова о привязке данных к ComboBox.
От:
Сергей
Дата: 26.03.09 08:37
Оценка:
Хм... Что есть Linq ?
Я использую студию 2005.
Она не знает что такое: System.Linq
А>Вот весь заголовок
А>А>using System;
А>using System.Collections;
А>using System.ComponentModel;
А>using System.Linq;
А>using System.Windows.Forms;
А>
Re[10]: Снова о привязке данных к ComboBox.
От:
solder
Дата: 26.03.09 08:50
Оценка:
Здравствуйте, Сергей, Вы писали:
С>Хм... Что есть Linq ?
С>Я использую студию 2005.
С>Она не знает что такое: System.Linq
Ну тогда ручками надо IEnumerable к object[] преобразовать.
Вообще, разницы нет, как хранить исходные данные. Мне проще в object[], чтоб по индексу искать.
Изначально всё это задумывалось, чтоб подменить "SelectedIndexChanged" на "SelectedItemChanged",
и чтоб динамически собраный DataSource не скидывал SelectedIndex в -1.
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить