2013-06-08 3 views
1

Я работаю с классом DesignSurface, и у меня возникла разочаровывающая проблема, которую я не могу понять. Я перетаскиваю элементы из своей панели инструментов и без проблем удаляю их в свою форму, но я хочу изменить свойства этих элементов, поскольку они помещаются на DesignSurface. Так, например, если я перетаскиваю ярлык на DesignSurface, я могу изменить значение BackColor элемента управления. Я знаю, что ToolboxItem предоставляет CreateComponents(), который принимает необязательный параметр свойств, но он вызывается API нижнего уровня, и я не вижу, где и как его переопределить, поэтому я могу предоставить свои собственные значения. У кого-нибудь есть идеи? Благодаря!Modify ToolboxItem во время перетаскивания

+0

Вы имеете в виду, что на вашем 'DesignSurface' есть некоторые элементы, и вы хотите изменить некоторые свойства этих элементов во время разработки (через окно« Свойства »)? Как выглядит ваш 'DesignSurface'? Это что-то вроде «Панели»? Ваш вопрос не достаточно ясен для меня. –

+0

DesignSurface - это UserControl. То, что я на самом деле пытаюсь сделать, это то, что когда пользователь бросает элемент управления в UserControl, я хочу изменить некоторые свойства этого элемента управления, прежде чем он будет фактически отображаться на поверхности. Конечно, если бы я хотел изменить значения элемента управления после того, как они были на DesignSurface, я просто настрою PropertyGrid. – dparsons

+0

Это немного странно для меня? Почему вы должны это делать? –

ответ

0

Хотя я чувствую, что это немного «взломанный», я не обязательно знаю, что это неправильно (и если это технически «неправильно», пожалуйста, оставьте мне отзыв о лучших практиках!), И он решил проблему на рука.

Что я в итоге сделал, это расширение ToolboxItem на основе прочитанной мной статьи MSDN.

public class SurfaceToolboxItem : ToolboxItem 
{ 
    private delegate void SetTextHandler(Control c, string text); 
    public string ReportFieldName { get; set; } 

    protected override IComponent[] CreateComponentsCore(IDesignerHost host) 
    { 
     var ctrl = (Label)host.CreateComponent(typeof(Label)); 
     var root = (Control) host.RootComponent; 

     root.BeginInvoke(new SetTextHandler(SetText), 
         new object[] {ctrl, ReportFieldName}); 

     return new IComponent[]{ ctrl }; 
    } 

    private void SetText(Control ctrl, string text) 
    { 
     ctrl.Text = text; 
    } 

} 

Некоторые очевидные недостатки:

  • Этот пункт будет только когда-либо создать контроль этикетки
  • Этот пункт будет только когда-либо установить свойство текста указанного управления этикетки на основе струнной собственности общественности.

Чтобы преодолеть эти проблемы, пункт может быть расширен, чтобы действовать как базовый ToolboxItem (реализующие CTOR принимающих параметр типа, что позволяет словарь имен собственности/ценностей, передаваемых в быть установлены после того, как тот факт, и т. д.)

Кроме того, это сломало функциональность перетаскивания с панели инструментов на поверхность дизайна, и это было особенно неприятно, потому что это было не слишком очевидно. Проблема была в моем методе DeserializeToolboxItem моей реализации Toolbox Service.

Первоначально это выглядело так:

ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject) 
{ 
    return (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem)); 
} 

Проблема заключалась в том, что приведение к ToolboxItem возвращается нуль, так как объект был типа SurfaceToolboxItem поэтому я изменил способ выглядеть следующим образом:

ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject) 
{ 
    var data = (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem)); 

    return data ?? (ToolboxItem)((DataObject)serializedObject).GetData(typeof(SurfaceToolboxItem)); 
} 

Таким образом, поддерживается как мое расширение, так и по умолчанию ToolboxItem.

1

Это не ответ, я просто хочу показать, что я нашел с вашей проблемой. Я думаю, у вас должен быть собственный способ доступа к вашему собственному Toolbox, и этот Toolbox реализует интерфейс IToolboxService, этот интерфейс имеет метод под названием GetSelectedToolboxItem(IDesignerHost). И я думаю, что вы должны реализовать этот метод, чтобы указать, как вы получаете выбранный элемент, я думаю, что ваш Toolbox должен иметь некоторый элемент управления, который содержит список элементов панели инструментов, это может быть ListBox ...

Вторая важная вещь это IDesignerHost, так как я понимаю, это может быть то, что вас интересует. Оно должно иметь какое-то отношение к вашему DesignSurface. Он имеет некоторые события для вас заинтересовать, как это:

IDesignerHost host = {some method to get it}; 
host.TransactionClosed += (s,e) => { 
    ICollection selected = ((ISelectionService)host.GetService(typeof(ISelectionService))).GetSelectedComponents();     
    IComponent[] comps = new IComponent[selected.Count]; 
    selected.CopyTo(comps, 0); 
    string displayName = YourToolBox.GetSelectedToolboxItem(host).DisplayName; 
    ((Control)comps[0]).Text = displayName; 
}; 

Я протестированные в проекте, который реализует очень сложный IDesignerHost, он имеет метод для меня, чтобы создать host для тестирования. При перетаскивании элемента управления на DesignSurface код по-прежнему не влияет на код TransactionClosed, я должен сделать что-то вроде Resizing, Moving..., и после этого возникает событие TransactionClosed и оно показывает DisplayName OK. Я не нахожу другого события лучше, самым подходящим событием должно быть ComponentAdded или ComponentAdding, но ни один из них не работает.

У меня есть еще один вопрос, образец проекта, который я пробовал, - это CustomFormsDesigner, который работает как другое обычное приложение Windows Forms, оно показывает панель инструментов, конструкцию и сетку свойств. Я делаю все после запуска. Но как насчет вашего дела? Я имею в виду, когда вы перетаскиваете свой элемент управления на свой DesignSurface, вы все еще находите время разработки в окне Visual Studio? или в вашем собственном приложении (как Designer)?

Должен сказать, что эта проблема настолько сложна для меня. Благодаря вам, я знаю об этом виде приложения.

+0

Эй, король короля. Несколько вещей. Я должен был быть более ясным: я на самом деле использую System.ComponentModel.Design.DesignSurface, поэтому большая часть работы с дизайнерами отвлекается от меня. Мой RootComponent имеет тип UserControl и ваш код работает, он запускается каждый раз, когда элемент управления добавляется к нему, но моя более конкретная проблема заключается в следующем: все «Инструменты» в моем ящике инструментов имеют тип Label, а их DisplayName установлен в имя поля в наборе данных отчета. Мне нужно значение DisplayName, чтобы я знал, в каком поле привязать элемент управления. Но я открыт для предложения – dparsons

+0

@abszero Я нашел проблему с моим решением, она работает только тогда, когда я перетаскиваю элемент управления из другого контейнера в форме на него, если перетаскивать новый из панели инструментов, это не Работа. Почему это работает для вас? Похоже, у вас есть свой собственный набор инструментов со своими «инструментами»? –

+0

У меня есть класс, который реализует IToolboxService, и у меня есть ListBox, который содержит несколько элементов ToolboxItem, которые замужем за этим классом. Затем я добавляю эту службу в свой DesignSurface. – dparsons

Смежные вопросы