Снова о привязке данных к 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);


Спасибо.
c# combobox binding
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.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.