Пошаговое руководство. Реализация редактирования по месту
Обновлен: Ноябрь 2007
В данном примере показано, как реализовать редактирование на месте для пользовательского элемента управления Windows Presentation Foundation (WPF). Эту функцию времени разработки можно использовать в Windows Presentation Foundation (WPF) для Visual Studio (конструктор) для присвоения значения свойству Content для пользовательского элемента управления «кнопка». В данном примере элемент управления является простой кнопкой, а графический элемент — текстовым полем, позволяющим изменять содержимое кнопки.
В данном пошаговом руководстве выполняются следующие задачи.
Создание проекта библиотеки пользовательских элементов управления WPF.
Создание отдельной сборки для метаданных времени разработки.
Реализация поставщика графических элементов для редактирования на месте.
Тестирование элемента управления во время разработки.
В результате будет полностью описан процесс создания поставщика графических элементов для пользовательского элемента управления.
Примечание. |
---|
Отображаемые диалоговые окна и команды меню могут отличаться от описанных в справке в зависимости от текущих параметров или версии среды. Для изменения параметров выберите пункт Импорт и экспорт параметров в меню Сервис. Дополнительные сведения см. в разделе Параметры Visual Studio. |
Обязательные компоненты
Ниже приведены компоненты, которые необходимы для выполнения данного пошагового руководства.
- Visual Studio 2008.
Создание пользовательского элемента управления
Первым этапом является создание проекта для пользовательского элемента управления. Этот элемент управления представляет собой простую кнопку, созданную с помощью небольшого количества кода, в котором для реализации поведения во время разработки используется метод GetIsInDesignMode.
Создание пользовательского элемента управления
Создайте новый проект библиотеки настраиваемых элементов управления WPF на языке Visual C# с именем CustomControlLibrary.
В редакторе кода откроется код для элемента управления CustomControl1.
В обозревателе решений измените имя файла с кодом на DemoControl.cs. Если появляется окно сообщения, запрашивающее подтверждение переименования всех ссылок в этом проекте, нажмите кнопку Да.
В обозревателе решений разверните папку «Themes».
Дважды щелкните файл Generic.xaml.
Файл Generic.xaml откроется в WPF (конструктор).
В представлении XAML замените все вхождения «CustomControl1» на «DemoControl».
Откройте файл DemoControl.cs в редакторе кода.
Замените автоматически создаваемый код на следующий код. Пользовательский элемент управления DemoControl является производным от класса Button
using System; using System.Windows; using System.Windows.Controls; namespace CustomControlLibrary { public class DemoControl : Button { } }
Задайте выходной путь проекта как «bin\».
Выполните построение решения.
Создание сборки метаданных времени разработки
Код времени разработки развертывается в особых сборках метаданных. Дополнительные сведения см. в разделе Практическое руководство. Использование хранилища метаданных. В данном пошаговом руководстве пользовательский графический элемент поддерживается только средой Visual Studio и развертывается в сборке с именем CustomControlLibrary.VisualStudio.Design.
Создание сборки метаданных времени разработки
Добавьте к решению новый проект библиотеки классов на языке Visual C# с именем CustomControlLibrary.VisualStudio.Design.
Задайте выходной путь проекта как «..\CustomControlLibrary\bin\». В этом случае сборка элемента управления и сборка метаданных будут находиться в одной папке, что обеспечит доступ к метаданным для конструкторов.
Добавьте ссылки на следующие сборки WPF:
PresentationCore
PresentationFramework
WindowsBase
Добавьте ссылки на следующие сборки WPF (конструктор):
Microsoft.Windows.Design
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
Добавьте ссылку на проект CustomControlLibrary.
В обозревателе решений измените имя файла с кодом «Class1» на Metadata.cs.
Замените автоматически создаваемый код на следующий код. Этот код создает таблицу AttributeTable, которая присоединяет пользовательскую реализацию времени разработки к классу DemoControl.
using System; using Microsoft.Windows.Design.Features; using Microsoft.Windows.Design.Metadata; namespace CustomControlLibrary.VisualStudio.Design { // Container for any general design-time metadata to initialize. // Designers look for a type in the design-time assembly that // implements IRegisterMetadata. If found, designers instantiate // this class and call its Register() method automatically. internal class Metadata : IRegisterMetadata { // Called by the designer to register any design-time metadata. public void Register() { AttributeTableBuilder builder = new AttributeTableBuilder(); // Add the adorner provider to the design-time metadata. builder.AddCustomAttributes( typeof(DemoControl), new FeatureAttribute(typeof(InplaceButtonAdorners))); MetadataStore.AddAttributeTable(builder.CreateTable()); } } }
Сохраните решение.
Реализация поставщика графических элементов
Поставщик графических элементов реализован в типе с именем InplaceButtonAdorners. Этот поставщик графических элементов позволяет пользователю устанавливать свойство элемента управления Content во время разработки.
Реализация поставщика графических элементов
Добавьте новый класс с именем InplaceButtonAdorners к проекту CustomControlLibrary.VisualStudio.Design.
В редакторе кода для класса InplaceButtonAdorners замените автоматически создаваемый код на следующий код. Этот код реализует поставщик PrimarySelectionAdornerProvider, который предоставляет графический элемент на основе элемента управления TextBox.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Shapes; using Microsoft.Windows.Design.Interaction; using System.Windows.Data; using System.Windows.Input; using System.ComponentModel; using Microsoft.Windows.Design.Model; namespace CustomControlLibrary.VisualStudio.Design { // The InplaceButtonAdorners class provides two adorners: // an activate glyph that, when clicked, activates in-place // editing, and an in-place edit control, which is a text box. internal class InplaceButtonAdorners : PrimarySelectionAdornerProvider { private Rectangle activateGlyph; private TextBox editGlyph; private AdornerPanel adornersPanel; public InplaceButtonAdorners() { adornersPanel = new AdornerPanel(); adornersPanel.IsContentFocusable = true; adornersPanel.Children.Add(ActivateGlyph); Adorners.Add(adornersPanel); } private UIElement ActivateGlyph { get { if (activateGlyph == null) { // The following code specifies the shape of the activate // glyph. This can also be implemented by using a XAML template. Rectangle glyph = new Rectangle(); glyph.Fill = AdornerColors.HandleFillBrush; glyph.Stroke = AdornerColors.HandleBorderBrush; glyph.RadiusX = glyph.RadiusY = 2; glyph.Width = 10; glyph.Height = 5; glyph.Cursor = Cursors.Hand; ToolTipService.SetToolTip( glyph, "Click to edit the text of the button. " + "Enter to commit, ESC to cancel."); // Position the glyph to the upper left of the DemoControl, // and slightly inside. AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.PositionRelativeToContentHeight(0, 10); placement.PositionRelativeToContentWidth(0, 5); placement.SizeRelativeToAdornerDesiredHeight(1, 0); placement.SizeRelativeToAdornerDesiredWidth(1, 0); AdornerPanel.SetPlacements(glyph, placement); // Add interaction to the glyph. A click starts in-place editing. ToolCommand command = new ToolCommand("ActivateEdit"); Task task = new Task(); task.InputBindings.Add(new InputBinding(command, new ToolGesture(ToolAction.Click))); task.ToolCommandBindings.Add(new ToolCommandBinding(command, OnActivateEdit)); AdornerProperties.SetTask(glyph, task); activateGlyph = glyph; } return activateGlyph; } } // When in-place editing is activated, a text box is placed // over the control and focus is set to its input task. // Its task commits itself when the user presses enter or clicks // outside the control. private void OnActivateEdit(object sender, ExecutedToolEventArgs args) { adornersPanel.Children.Remove(ActivateGlyph); adornersPanel.Children.Add(EditGlyph); // Once added, the databindings activate. // All the text can now be selected. EditGlyph.SelectAll(); EditGlyph.Focus(); GestureData data = GestureData.FromEventArgs(args); Task task = AdornerProperties.GetTask(EditGlyph); task.Description = "Edit text"; task.BeginFocus(data); } // The EditGlyph utility property creates a TextBox to use as // the in-place editing control. This property centers the TextBox // inside the target control and sets up data bindings between // the TextBox and the target control. private TextBox EditGlyph { get { if (editGlyph == null) { TextBox glyph = new TextBox(); glyph.BorderThickness = new Thickness(0); glyph.Margin = new Thickness(4); AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.PositionRelativeToContentWidth(0, 0); placement.PositionRelativeToContentHeight(0, 0); placement.SizeRelativeToContentHeight(1, 0); placement.SizeRelativeToContentWidth(1, 0); AdornerPanel.SetPlacements(glyph, placement); // Data bind the glyph's vertical and horizontal alignment // to the target control's alignment properties. Binding binding = new Binding(); binding.Source = glyph; binding.Path = new PropertyPath( "(0).(1)", AdornerProperties.ActualViewProperty, Button.HorizontalContentAlignmentProperty); glyph.SetBinding(TextBox.HorizontalContentAlignmentProperty, binding); binding = new Binding(); binding.Source = glyph; binding.Path = new PropertyPath( "(0).(1)", AdornerProperties.ActualViewProperty, Button.VerticalContentAlignmentProperty); glyph.SetBinding(TextBox.VerticalContentAlignmentProperty, binding); // Make the glyph's background match the control's background. binding = new Binding(); binding.Source = glyph; binding.Path = new PropertyPath( "(0).(1)", AdornerProperties.ActualViewProperty, Button.BackgroundProperty); glyph.SetBinding(TextBox.BackgroundProperty, binding); // Two-way data bind the text box's text property to content. binding = new Binding(); binding.Source = glyph; binding.Path = new PropertyPath("(0).(1)[Content].(2)", AdornerProperties.ActualModelProperty, TypeDescriptor.GetProperties( typeof(ModelItem))["Properties"], TypeDescriptor.GetProperties( typeof(ModelProperty))["ComputedValue"]); binding.Mode = BindingMode.TwoWay; binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; binding.Converter = new ContentConverter(); glyph.SetBinding(TextBox.TextProperty, binding); // Create a task that describes the UI interaction. ToolCommand commitCommand = new ToolCommand("Commit Edit"); Task task = new Task(); task.InputBindings.Add( new InputBinding( commitCommand, new KeyGesture(Key.Enter))); task.ToolCommandBindings.Add( new ToolCommandBinding(commitCommand, delegate { task.Complete(); })); task.FocusDeactivated += delegate { adornersPanel.Children.Remove(EditGlyph); adornersPanel.Children.Add(ActivateGlyph); }; AdornerProperties.SetTask(glyph, task); editGlyph = glyph; } return editGlyph; } } // The ContentConverter class ensures that only strings // are assigned to the Text property of EditGlyph. private class ContentConverter : IValueConverter { public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is string) { return value; } return string.Empty; } public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; } } } }
Выполните построение решения.
Тестирование реализации времени разработки
Класс DemoControl можно использовать как любой другой элемент управления WPF. WPF (конструктор) управляет созданием всех объектов времени разработки.
Тестирование реализации времени разработки
Добавьте к решению новый проект приложения WPF на языке Visual C# с именем DemoApplication.
В WPF (конструктор) откроется файл Window1.xaml.
Добавьте ссылку на проект CustomControlLibrary.
В представлении XAML замените автоматически созданный код XAML на следующий код XAML. Этот код XAML добавляет ссылку на пространство имен CustomControlLibrary и пользовательский элемент управления DemoControl. Если элемент управления не отображается, можно щелкнуть панели информации в верхней части конструктора для перезагрузки представления.
<Window x:Class="DemoApplication.Window1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:ccl="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary" Title="Window1" Height="300" Width="300"> <Grid> <ccl:DemoControl></ccl:DemoControl> </Grid> </Window>
Вновь Выполните сборку решения.
В представлении конструктора выберите элемент управления DemoControl.
Небольшой глиф Rectangle появится в верхнем левом углу элемента управления DemoControl.
Щелкните глиф Rectangle для активации режима редактирования на месте.
Появится текстовое поле, в котором отображается свойство Content элемента управления DemoControl. Поскольку содержимое в настоящий момент пусто, будет виден только курсор в центре кнопки.
Введите новое значение для текстового содержимого, затем нажмите клавишу ВВОД.
В представлении XAML свойству Content присваивается текстовое значение, введенное в представлении конструктора.
Сделайте проект DemoApplication автоматически загружаемым проектом и запустите решение.
Во время выполнения проекта кнопка имеет текстовое значение, заданное графическим элементом.
Следующие действия
Можно добавить дополнительные пользовательские функции времени разработки для пользовательских элементов управления.
Добавьте MenuAction к пользовательским элементам времени разработки. Дополнительные сведения см. в разделе Пошаговое руководство. Создание элемента MenuAction.
Создайте пользовательский редактор цвета, который можно использовать в окне «Свойства». Дополнительные сведения см. в разделе Пошаговое руководство. Реализация редактора цвета.
Создайте пользовательский графический элемент для задания параметра непрозрачности элемента управления. Дополнительные сведения см. в разделе Пошаговое руководство. Создание графического элемента времени разработки.