Недавно начал работать с C# и
накопилось вот несколько вопросов, может поможет кто:
1) Свойства своих классов в дизайнере
Есть мой контрол (MyControl) — лейбл имеющий рамку и текст которые умеют моргать и менять цвета, наследованный от UserControl, который использует мои классы не наследованные ни от чего (MyText, MyBorder) — они собственно и умеют моргать и менять цвета
Так вот — как заставить дизайнер отображать и изменять свойства MyText и MyBorder, чтобы они выбирались в ToolBox'е как выпадающий список свойств, а не определяя свойства этих классов как свойства MyControl?
2) Групповое переименование контролов в дизайнере
Есть тот же MyControl. На форме их может быть очень много (20-60 штук), разделенных на группы по именам (т.е. MyControl_A1..n, MyControl_B1..n, MyControl_C1..n) и они кидаются на форму вручную (в основном Ctrl+C, Ctrl+V)
Как сделать так, чтобы можно было переименовать группу контролов (MyControl1..n) -> (MyControl_A1..n), или, если можно написать, чтобы при копировании контрола копировались не только свойства но и имя его, тока индекс новый?
3) Индексация контролов
Как получить доступ к одному контролу из группы (могут быть в разных контейнерах типа панель) по индексу?
Придумал только вариант выделения индекса из имени контрола:
Control[] cc;
for (int i = 1; i < n+1; i++)
{
cc = this.Controls.Find("MyControl" + i.ToString(), true);
if (cc.Length == 0) continue;
MyControls.MyControl objControl;
objControl = (MyControls.MyControl)cc[0];
}
может вы знаете лучший вариант?
Заранее спасибо всем отвечающим.
15.01.08 10:51: Перенесено модератором из '.NET' — Хитрик Денис
Re: Свои контролы в C# (работа с ними из дизайнера)
AZ>1) Свойства своих классов в дизайнере AZ>Есть мой контрол (MyControl) — лейбл имеющий рамку и текст которые умеют моргать и менять цвета, наследованный от UserControl, который использует мои классы не наследованные ни от чего (MyText, MyBorder) — они собственно и умеют моргать и менять цвета AZ> Так вот — как заставить дизайнер отображать и изменять свойства MyText и MyBorder, чтобы они выбирались в ToolBox'е как выпадающий список свойств, а не определяя свойства этих классов как свойства MyControl?
Не понятно что куда должно выпадать. Можно например прицепить к Mytext и MyBorder атрибут ExpandableObjectConverter.
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MyBorder
{
...
}
Тогда свойство MyBorder будет распахиваться в дизайнере как например Font.
AZ>2) Групповое переименование контролов в дизайнере AZ>Есть тот же MyControl. На форме их может быть очень много (20-60 штук), разделенных на группы по именам (т.е. MyControl_A1..n, MyControl_B1..n, MyControl_C1..n) и они кидаются на форму вручную (в основном Ctrl+C, Ctrl+V) AZ>Как сделать так, чтобы можно было переименовать группу контролов (MyControl1..n) -> (MyControl_A1..n), или, если можно написать, чтобы при копировании контрола копировались не только свойства но и имя его, тока индекс новый?
Посмотрите метод InitializeNewComponent класса ComponentDesigner. Еще есть класс DesignerSurface и у него ResolveName.
Хотя тут надо определиться с вопросом "а зачем это надо" и тогда искать решения.
AZ>3) Индексация контролов AZ>Как получить доступ к одному контролу из группы (могут быть в разных контейнерах типа панель) по индексу? AZ>Придумал только вариант выделения индекса из имени контрола:
Возможно подойдет IExtenderProvider.
Re[2]: Свои контролы в C# (работа с ними из дизайнера)
Здравствуйте, Pavel_Agurov, Вы писали:
P_A>Не понятно что куда должно выпадать. Можно например прицепить к Mytext и MyBorder атрибут ExpandableObjectConverter.
P_A>Тогда свойство MyBorder будет распахиваться в дизайнере как например Font.
так и нужно, чтобы свойства распахивались как например Font
А можно подробнее про [TypeConverter(typeof(ExpandableObjectConverter))] — я поставил этот атрибут перед классом MyBorder но желаемого не получил — свойство Border стало просто доступно в Properties window, но не распахивается.. Может надо еще что-то писать в коде?
А свойство Border я определяю в MyControl как
public MyBorder Border
{
get { return _border; }
set { _border = value; this.Invalidate(); }
}
Перед этим никакого атрибута ставить не надо? (атрибуты для меня пока неизведанная до конца штука)
P_A>Посмотрите метод InitializeNewComponent класса ComponentDesigner. Еще есть класс DesignerSurface и у него ResolveName. P_A>Хотя тут надо определиться с вопросом "а зачем это надо" и тогда искать решения.
Не совсем понятно как использовать эти классы — наследовать свой MyBorder от него(них) или писать как в примере MSDN свой класс-дизайнер наследованный от них? Тогда встает вопрос как его использовать.. Если можно напишите подробнее..
спасибо за подсказки, хоть понятно в какую сторону копать. )
Re[3]: Свои контролы в C# (работа с ними из дизайнера)
AZ>А можно подробнее про [TypeConverter(typeof(ExpandableObjectConverter))] — я поставил этот атрибут перед классом MyBorder но желаемого не получил — свойство Border стало просто доступно в Properties window, но не распахивается.. AZ>А свойство Border я определяю в MyControl как
AZ>
AZ> public MyBorder Border
AZ> {
AZ> get { return _border; }
AZ> set { _border = value; this.Invalidate(); }
AZ> }
AZ>
надо чтобы MyBorder имело public свойства (не поля, а именно свойства).
P_A>>Посмотрите метод InitializeNewComponent класса ComponentDesigner. Еще есть класс DesignerSurface и у него ResolveName. P_A>>Хотя тут надо определиться с вопросом "а зачем это надо" и тогда искать решения. AZ> Не совсем понятно как использовать эти классы — наследовать свой MyBorder от него(них) или писать как в примере MSDN свой класс-дизайнер наследованный от них? Тогда встает вопрос как его использовать.. Если можно напишите подробнее..
вообще это не дает ответа на вопрос "зачем это надо" и что вы хотите сделать. Зачем наследовать MyBorder от чего либо, если вы хотите просто задавать имена своим компонентам? Или я что-то не понимаю. Опишите четко задачу.
Re[4]: Свои контролы в C# (работа с ними из дизайнера)
Здравствуйте, Pavel_Agurov, Вы писали:
AZ>>[TypeConverter(typeof(ExpandableObjectConverter))] — я поставил этот атрибут перед классом MyBorder но желаемого не получил — свойство Border стало просто доступно в Properties window, но не распахивается..
.. P_A>надо чтобы MyBorder имело public свойства (не поля, а именно свойства).
Спасибо большое, заработало! Хотя и непонятно почему вчера не работало — у MyBorder были public свойства.. Я просто еще добавил..
P_A>вообще это не дает ответа на вопрос "зачем это надо" и что вы хотите сделать. Зачем наследовать MyBorder от чего либо, если вы хотите просто задавать имена своим компонентам? Или я что-то не понимаю. Опишите четко задачу.
Хоть этот вопрос и не настолько актуален уже, но все же интересно, можно ли так сделать..
Значит имеем контрол MyControl. Другой человек будет делать формы с этим контролом. Форм будет 20-30 штук и на каждой будет 20-60 этих контролов.
С этими формами работает один и тот же код, которому без разницы что за форма и сколько их, потому что он работает с именами контролов, выделяя из них группу и индекс.
Т.о. на каждой форме надо дать контролам имена по группам и индексам: MyControl_A1..n, MyControl_B1..m, MyControl_C1..k, где n,m,k — количество контролов в разной группе. Разным группам контролов присваиваются разные свойства (их довольно много).
Задача состоит в том, чтобы облегчить жизнь человеку, который будет делать эти формы. Т.е. сделать так, чтобы можно было кинуть на форму один контрол, задать ему нужные свойства и имя, и скопировать\вставить его столько раз сколько их таких требуется, причем в имени должна меняться только последняя цифра. Или сделать еще как-нибудь, но чтобы избавится от необходимости каждый раз давать имя контролу.
В общем вот так ) надеюсь, не сильно напрягаю своим непрофессионализмом..
Re[5]: Свои контролы в C# (работа с ними из дизайнера)
Здравствуйте, AndrewZomb, Вы писали:
AZ>Хоть этот вопрос и не настолько актуален уже, но все же интересно, можно ли так сделать.. AZ>Значит имеем контрол MyControl. Другой человек будет делать формы с этим контролом. Форм будет 20-30 штук и на каждой будет 20-60 этих контролов. AZ>С этими формами работает один и тот же код, которому без разницы что за форма и сколько их, потому что он работает с именами контролов, выделяя из них группу и индекс. AZ> Т.о. на каждой форме надо дать контролам имена по группам и индексам: MyControl_A1..n, MyControl_B1..m, MyControl_C1..k, где n,m,k — количество контролов в разной группе. Разным группам контролов присваиваются разные свойства (их довольно много). AZ>Задача состоит в том, чтобы облегчить жизнь человеку, который будет делать эти формы. Т.е. сделать так, чтобы можно было кинуть на форму один контрол, задать ему нужные свойства и имя, и скопировать\вставить его столько раз сколько их таких требуется, причем в имени должна меняться только последняя цифра. Или сделать еще как-нибудь, но чтобы избавится от необходимости каждый раз давать имя контролу.
зачем хранить данные в имени переменной?
для привязки любых данных к контролу есть замечательное свойство Tag
myControl.Tag = new Tuple<char, int, char>('B', 1, 'm');
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[6]: Свои контролы в C# (работа с ними из дизайнера)
От:
Аноним
Дата:
15.01.08 09:56
Оценка:
Здравствуйте, Ziaw, Вы писали:
Z>зачем хранить данные в имени переменной? Z>для привязки любых данных к контролу есть замечательное свойство Tag
Z>
Z> myControl.Tag = new Tuple<char, int, char>('B', 1, 'm');
Z>
Да я знаю что в Tag можно поместить любой объект, но тогда как человек, делающий формы будет заполнять эти данные? А как обратиться к нужному контролу зная его данные? Если только перебирать все и сравнивать..
В общем свои тут тоже не все просто..
Re[5]: Свои контролы в C# (работа с ними из дизайнера)
AZ>Хоть этот вопрос и не настолько актуален уже, но все же интересно, можно ли так сделать.. AZ>Значит имеем контрол MyControl. Другой человек будет делать формы с этим контролом. Форм будет 20-30 штук и на каждой будет 20-60 этих контролов. AZ>С этими формами работает один и тот же код, которому без разницы что за форма и сколько их, потому что он работает с именами контролов, выделяя из них группу и индекс. AZ> Т.о. на каждой форме надо дать контролам имена по группам и индексам: MyControl_A1..n, MyControl_B1..m, MyControl_C1..k, где n,m,k — количество контролов в разной группе. Разным группам контролов присваиваются разные свойства (их довольно много). AZ>Задача состоит в том, чтобы облегчить жизнь человеку, который будет делать эти формы. Т.е. сделать так, чтобы можно было кинуть на форму один контрол, задать ему нужные свойства и имя, и скопировать\вставить его столько раз сколько их таких требуется, причем в имени должна меняться только последняя цифра. Или сделать еще как-нибудь, но чтобы избавится от необходимости каждый раз давать имя контролу.
Вообще-то все равно не понятно что такое группа. Если группа — это компоненты, объедененные по имени (с разными номерами), то как собственно тогда задавать это имя, если не задав имя не понятно в какой он группе?
Предложу решение, которое можно расширить по необходимости. Недостаток имени в том что его нельзя задать всем контролам одновременно, но можно добавить свойство всем компонентам и задавать его, как это делает например tooltip.
Посему далаем так. Создаем компонент, реализующий IExtenderProvider, т.е. он будет добавлять ВСЕМ компонентам свойство GroupIndex:
[ProvideProperty("GroupIndex", typeof(Control))]
[DesignerAttribute(typeof(GroupIndexerDesigner))]
public class GroupIndexer : Component, IExtenderProvider
{
private Hashtable hashIndexs;
private IList<Component> components;
public GroupIndexer()
{
hashIndexs = new Hashtable();
components = new List<Component>();
}
~GroupIndexer()
{
Dispose(false);
}
public bool CanExtend(object extendee)
{
if (extendee is Control && !(extendee is GroupIndexer) && !(extendee is Form))
{
return true;
}
return false;
}
public int GetGroupIndex(Control parent)
{
if (hashIndexs.Contains(parent))
{
return (int)hashIndexs[parent];
}
else
{
return 0;
}
}
public void SetGroupIndex(Control parent, int value)
{
if (value == 0)
{
hashIndexs.Remove(parent);
components.Remove(parent);
}
else
{
if (hashIndexs.Contains(parent))
{
hashIndexs[parent] = value;
}
else
{
hashIndexs.Add(parent, value);
components.Add(parent);
}
}
}
// Освобождение ресурсовprotected override void Dispose(bool disposing)
{
if (disposing)
{
hashIndexs.Clear();
hashIndexs = null;
components.Clear();
components = null;
}
base.Dispose(disposing);
}
public IList<Component> Components
{
get
{
return components;
}
}
}
Если индекс не 0, то компонент считается входящим в группу. Если 0 — удаляем из групп.
Дизайнер компонента очень простой. Он только добавляет меню:
public class GroupIndexerDesigner : ComponentDesigner
{
private DesignerActionListCollection actionLists;
public override DesignerActionListCollection ActionLists
{
get
{
// Если еще не создавали actionListif (actionLists == null)
{
// Создаем ActionList
actionLists = new DesignerActionListCollection();
// Добавляем тег
actionLists.Add(new TooltipsActionList(this.Component));
}
return actionLists;
}
}
}
Меню описывается так:
public class GroupIndexActionList : DesignerActionList
{
GroupIndexer component;
DesignerActionUIService designerActionUIService;
public GroupIndexActionList(IComponent component)
: base(component)
{
// Сохраняем ссылку на редактируемый компонентthis.component = component as GroupIndexer;
// Сохраняем ссылку на ActionList сервис
designerActionUIService = GetService(typeof(DesignerActionUIService)) as DesignerActionUIService;
}
public void ApplyName()
{
IList<Component> list = component.Components;
for (int i = 0; i < list.Count; i++)
{
list[i].Site.Name = "group_"+i.ToString();
}
}
public override DesignerActionItemCollection GetSortedActionItems()
{
DesignerActionItemCollection items = new DesignerActionItemCollection();
items.Add(new DesignerActionMethodItem(this, "ApplyName", "ApplyName"));
return items;
}
}
Собвстенно вся работа производится в методе ApplyName, который пока просто переименовывает все компоненты, у которых индекс не 0. А по идее должен раскидывать имена согласно группам. Ну это уже дело техники, а мне лень...
Процесс выглядит так: накидываем компонентов, добавляем на форму GroupIndexer, выделяем первую группу и массово задаем индекс 1, затем вторую и т.д. Потом тыкаем в GroupIndexer и вызываем меню ApplyName. Оно все переименовывает махом.
Сюда надо будет добавить логики проверки если вдруг имена пересекуться и т.д. Но это уже на любителя.
Re[6]: Свои контролы в C# (работа с ними из дизайнера)