Пошаговое руководство. Отладка пользовательских элементов управления WPF во время разработки
Обновлен: Ноябрь 2007
В данном примере показано, как отладить графический элемент времени разработки для пользовательского элемента управления Windows Presentation Foundation (WPF). Графический элемент является флажком, который предоставляет простую возможность автоматического масштабирования.
В данном пошаговом руководстве выполняются следующие задачи.
Создание проекта библиотеки пользовательских элементов управления WPF.
Создание отдельной сборки для метаданных времени разработки.
Реализация поставщика графических элементов.
Тестирование элемента управления во время разработки.
Настройка проекта для отладки во время разработки.
Отладка элемента управления во время разработки.
В результате, будет полностью описан процесс отладки графического элемента для пользовательского элемента управления.
Примечание. |
---|
Отображаемые диалоговые окна и команды меню могут отличаться от описанных в справке в зависимости от текущих параметров или версии среды. Для изменения параметров выберите пункт Импорт и экспорт параметров в меню Сервис. Дополнительные сведения см. в разделе Параметры Visual Studio. |
Обязательные компоненты
Ниже приведены компоненты, которые необходимы для выполнения данного пошагового руководства.
- Visual Studio 2008.
Создание пользовательского элемента управления
Первым этапом является создание проекта для пользовательского элемента управления. Этот элемент управления представляет собой кнопку, созданную с помощью небольшого количества кода, в котором для реализации поведения во время разработки используется метод GetIsInDesignMode.
Создание пользовательского элемента управления
Создайте новый проект библиотеки пользовательских элементов управления WPF на языке Visual Basic или Visual C# с именем AutoSizeButtonLibrary.
В редакторе кода откроется код для элемента управления CustomControl1.
В обозревателе решений измените имя файла с кодом на AutoSizeButton.cs или AutoSizeButton.vb. Если появляется окно сообщения, запрашивающее подтверждение переименования всех ссылок в этом проекте, нажмите кнопку Да.
В обозревателе решений разверните папку "Themes".
Дважды щелкните файл Generic.xaml.
Файл Generic.xaml откроется в WPF (конструктор).
В представлении XAML замените все вхождения "CustomControl1" на "AutoSizeButton".
Откройте файл AutoSizeButton.cs или AutoSizeButton.vb в редакторе кода.
Замените автоматически создаваемый код на следующий код. Этот код наследует от класса Button и отображает текст "Режим разработки активен", когда кнопка появляется в конструкторе.
Imports System Imports System.Collections.Generic Imports System.Text Imports System.Windows.Controls Imports System.Windows.Media Imports System.ComponentModel ' The AutoSizeButton control implements a button ' with a custom design-time experience. Public Class AutoSizeButton Inherits Button Public Sub New() ' The following code enables custom design-mode logic. ' The GetIsInDesignMode check and the following design-time ' code are optional and shown only for demonstration. If DesignerProperties.GetIsInDesignMode(Me) Then Content = "Design mode active" End If End Sub End Class
using System; using System.Collections.Generic; using System.Text; using System.Windows.Controls; using System.Windows.Media; using System.ComponentModel; namespace AutoSizeButtonLibrary { // The AutoSizeButton control implements a button // with a custom design-time experience. public class AutoSizeButton : Button { public AutoSizeButton() { // The following code enables custom design-mode logic. // The GetIsInDesignMode check and the following design-time // code are optional and shown only for demonstration. if (DesignerProperties.GetIsInDesignMode(this)) { Content = "Design mode active"; } } } }
Задайте выходной путь проекта как "bin\".
Выполните построение решения.
Создание сборки метаданных времени разработки
Код времени разработки развертывается в специальных сборках метаданных. В данном примере пользовательский графический элемент развертывается в сборке с именем AutoSizeButtonLibrary.VisualStudio.Design. Дополнительные сведения см. в разделе Хранилище метаданных.
Создание сборки метаданных времени разработки
Добавьте к решению новый проект библиотеки классов на языке Visual Basic или Visual C# с именем AutoSizeButtonLibrary.VisualStudio.Design.
Задайте выходной путь проекта как "..\AutoSizeButtonLibrary\bin\". В этом случае сборка элемента управления и сборка метаданных будут находиться в одной папке, что обеспечит доступ к метаданным для конструкторов.
Добавьте ссылки на следующие сборки WPF:
PresentationCore
PresentationFramework
WindowsBase.
Добавьте ссылки на следующие сборки WPF (конструктор):
Microsoft.Windows.Design
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
Добавьте ссылку на проект AutoSizeButtonLibrary
В обозревателе решений измените имя файла с кодом "Class1" на Metadata.cs или Metadata.vb. При появлении окна сообщения, запрашивающего подтверждение переименования всех ссылок в этом проекте, нажмите кнопку Да.
Замените автоматически создаваемый код на следующий код. Этот код создает таблицу AttributeTable, которая присоединяет пользовательскую реализацию времени разработки к классу AutoSizeButton.
Imports System Imports System.Collections.Generic Imports System.Text Imports System.ComponentModel Imports System.Windows.Media Imports System.Windows.Controls Imports System.Windows Imports AutoSizeButtonLibrary Imports Microsoft.Windows.Design.Features Imports Microsoft.Windows.Design.Metadata Imports AutoSizeButtonLibrary.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. Friend Class Metadata Implements IRegisterMetadata ' Called by the designer to register any design-time metadata. Public Sub Register() Implements IRegisterMetadata.Register Dim builder As New AttributeTableBuilder() builder.AddCustomAttributes(GetType(AutoSizeButton), New FeatureAttribute(GetType(AutoSizeAdornerProvider))) MetadataStore.AddAttributeTable(builder.CreateTable()) End Sub End Class
using System; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.Windows.Media; using System.Windows.Controls; using System.Windows; using AutoSizeButtonLibrary; using Microsoft.Windows.Design.Features; using Microsoft.Windows.Design.Metadata; using AutoSizeButtonLibrary.VisualStudio.Design; namespace AutoSizeButtonLibrary.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(); builder.AddCustomAttributes( typeof(AutoSizeButton), new FeatureAttribute(typeof(AutoSizeAdornerProvider))); MetadataStore.AddAttributeTable(builder.CreateTable()); } } }
Сохраните решение.
Реализация поставщика графических элементов
Поставщик графических элементов реализован в типе с именем AutoSizeAdornerProvider. Этот поставщик графических элементов FeatureProvider поддерживает задание свойств Height и Width элемента управления во время разработки.
Реализация поставщика графических элементов
Добавьте новый класс с именем AutoSizeAdornerProvider к проекту AutoSizeButtonLibrary.VisualStudio.Design .
В редакторе кода для поставщика AutoSizeAdornerProvider замените автоматически создаваемый код на следующий код. Этот код реализует поставщик PrimarySelectionAdornerProvider, который предоставляет графический элемент на основе элемента управления CheckBox.
Imports System Imports System.Collections.Generic Imports System.Text Imports System.Windows.Input Imports System.Windows Imports System.Windows.Automation Imports System.Windows.Controls Imports System.Windows.Media Imports System.Windows.Shapes Imports Microsoft.Windows.Design.Interaction Imports Microsoft.Windows.Design.Model ' The following class implements an adorner provider for the ' AutoSizeButton control. The adorner is a CheckBox control, which ' changes the Height and Width of the AutoSizeButton to "Auto", ' which is represented by double.NaN. Public Class AutoSizeAdornerProvider Inherits PrimarySelectionAdornerProvider Private settingProperties As Boolean Private adornedControlModel As ModelItem Private autoSizeCheckBox As CheckBox Private autoSizeAdornerPanel As AdornerPanel ' The constructor sets up the adorner control. Public Sub New() autoSizeCheckBox = New CheckBox() autoSizeCheckBox.Content = "AutoSize" autoSizeCheckBox.IsChecked = True autoSizeCheckBox.FontFamily = AdornerFonts.FontFamily autoSizeCheckBox.FontSize = AdornerFonts.FontSize autoSizeCheckBox.Background = CType( _ AdornerResources.FindResource(AdornerColors.RailFillBrushKey), _ Brush) End Sub ' The following method is called when the adorner is activated. ' It creates the adorner control, sets up the adorner panel, ' and attaches a ModelItem to the AutoSizeButton. Protected Overrides Sub Activate(ByVal item As ModelItem, ByVal view As DependencyObject) ' Save the ModelItem and hook into when it changes. ' This enables updating the slider position when ' a new background value is set. adornedControlModel = item AddHandler adornedControlModel.PropertyChanged, AddressOf AdornedControlModel_PropertyChanged ' All adorners are placed in an AdornerPanel ' for sizing and layout support. Dim panel As AdornerPanel = Me.Panel ' Set up the adorner's placement. Dim placement As New AdornerPlacementCollection() AdornerPanel.SetHorizontalStretch(autoSizeCheckBox, AdornerStretch.None) AdornerPanel.SetVerticalStretch(autoSizeCheckBox, AdornerStretch.None) panel.CoordinateSpace = AdornerCoordinateSpaces.Layout placement.SizeRelativeToAdornerDesiredWidth(1.0, 0) placement.SizeRelativeToAdornerDesiredHeight(1.0, 0) placement.PositionRelativeToAdornerHeight(-1.0, -23) placement.PositionRelativeToAdornerWidth(0, -23) AdornerPanel.SetPlacements(autoSizeCheckBox, placement) ' Listen for changes to the checked state. AddHandler autoSizeCheckBox.Checked, AddressOf autoSizeCheckBox_Checked AddHandler autoSizeCheckBox.Unchecked, AddressOf autoSizeCheckBox_Unchecked ' Run the base implementation. MyBase.Activate(item, view) End Sub ' The Panel utility property demand-creates the ' adorner panel and adds it to the provider's ' Adorners collection. Public ReadOnly Property Panel() As AdornerPanel Get If Me.autoSizeAdornerPanel Is Nothing Then Me.autoSizeAdornerPanel = New AdornerPanel() ' Add the adorner to the adorner panel. Me.autoSizeAdornerPanel.Children.Add(autoSizeCheckBox) ' Add the panel to the Adorners collection. Adorners.Add(autoSizeAdornerPanel) End If Return Me.autoSizeAdornerPanel End Get End Property ' The following code handles the Checked event. ' It autosizes the adorned control's Height and Width. Sub autoSizeCheckBox_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs) Me.SetHeightAndWidth(True) End Sub ' The following code handles the Unchecked event. ' It sets the adorned control's Height and Width to a hard-coded value. Sub autoSizeCheckBox_Unchecked(ByVal sender As Object, ByVal e As RoutedEventArgs) Me.SetHeightAndWidth(False) End Sub ' The SetHeightAndWidth utility method sets the Height and Width ' properties through the model and commits the change. Private Sub SetHeightAndWidth(ByVal [auto] As Boolean) settingProperties = True Dim batchedChange As ModelEditingScope = adornedControlModel.BeginEdit() Try Dim widthProperty As ModelProperty = adornedControlModel.Properties(Control.WidthProperty) Dim heightProperty As ModelProperty = adornedControlModel.Properties(Control.HeightProperty) If [auto] Then widthProperty.ClearValue() heightProperty.ClearValue() Else widthProperty.SetValue(20.0) heightProperty.SetValue(20.0) End If batchedChange.Complete() Finally batchedChange.Dispose() settingProperties = False End Try End Sub ' The following method deactivates the adorner. Protected Overrides Sub Deactivate() RemoveHandler adornedControlModel.PropertyChanged, _ AddressOf AdornedControlModel_PropertyChanged MyBase.Deactivate() End Sub ' The following method handles the PropertyChanged event. Sub AdornedControlModel_PropertyChanged( _ ByVal sender As Object, _ ByVal e As System.ComponentModel.PropertyChangedEventArgs) If settingProperties Then Return If e.PropertyName = "Height" Or e.PropertyName = "Width" Then Dim h As Double = CType(adornedControlModel.Properties(Control.HeightProperty).ComputedValue, Double) Dim w As Double = CType(adornedControlModel.Properties(Control.WidthProperty).ComputedValue, Double) If Double.IsNaN(h) And Double.IsNaN(w) Then autoSizeCheckBox.IsChecked = True Else autoSizeCheckBox.IsChecked = False End If End If End Sub End Class
using System; using System.Collections.Generic; using System.Text; using System.Windows.Input; using System.Windows; using System.Windows.Automation; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; using Microsoft.Windows.Design.Interaction; using Microsoft.Windows.Design.Model; namespace AutoSizeButtonLibrary.VisualStudio.Design { // The following class implements an adorner provider for the // AutoSizeButton control. The adorner is a CheckBox control, which // changes the Height and Width of the AutoSizeButton to "Auto", // which is represented by double.NaN. public class AutoSizeAdornerProvider : PrimarySelectionAdornerProvider { bool settingProperties; private ModelItem adornedControlModel; CheckBox autoSizeCheckBox; AdornerPanel autoSizeAdornerPanel; // The constructor sets up the adorner control. public AutoSizeAdornerProvider() { autoSizeCheckBox = new CheckBox(); autoSizeCheckBox.Content = "AutoSize"; autoSizeCheckBox.IsChecked = true; autoSizeCheckBox.FontFamily = AdornerFonts.FontFamily; autoSizeCheckBox.FontSize = AdornerFonts.FontSize; autoSizeCheckBox.Background = AdornerResources.FindResource( AdornerColors.RailFillBrushKey) as Brush; } // The following method is called when the adorner is activated. // It creates the adorner control, sets up the adorner panel, // and attaches a ModelItem to the AutoSizeButton. protected override void Activate(ModelItem item, DependencyObject view) { // Save the ModelItem and hook into when it changes. // This enables updating the slider position when // a new background value is set. adornedControlModel = item; adornedControlModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler( AdornedControlModel_PropertyChanged); // All adorners are placed in an AdornerPanel // for sizing and layout support. AdornerPanel panel = this.Panel; // Set up the adorner's placement. AdornerPlacementCollection placement = new AdornerPlacementCollection(); AdornerPanel.SetHorizontalStretch(autoSizeCheckBox, AdornerStretch.None); AdornerPanel.SetVerticalStretch(autoSizeCheckBox, AdornerStretch.None); panel.CoordinateSpace = AdornerCoordinateSpaces.Layout; placement.SizeRelativeToAdornerDesiredWidth(1.0, 0); placement.SizeRelativeToAdornerDesiredHeight(1.0, 0); placement.PositionRelativeToAdornerHeight(-1.0, -23); placement.PositionRelativeToAdornerWidth(0, -23); AdornerPanel.SetPlacements(autoSizeCheckBox, placement); // Listen for changes to the checked state. autoSizeCheckBox.Checked += new RoutedEventHandler(autoSizeCheckBox_Checked); autoSizeCheckBox.Unchecked += new RoutedEventHandler(autoSizeCheckBox_Unchecked); // Run the base implementation. base.Activate(item, view); } // The Panel utility property demand-creates the // adorner panel and adds it to the provider's // Adorners collection. private AdornerPanel Panel { get { if (this.autoSizeAdornerPanel == null) { autoSizeAdornerPanel = new AdornerPanel(); // Add the adorner to the adorner panel. autoSizeAdornerPanel.Children.Add(autoSizeCheckBox); // Add the panel to the Adorners collection. Adorners.Add(autoSizeAdornerPanel); } return this.autoSizeAdornerPanel; } } // The following code handles the Checked event. // It autosizes the adorned control's Height and Width. void autoSizeCheckBox_Checked(object sender, RoutedEventArgs e) { this.SetHeightAndWidth(true); } // The following code handles the Unchecked event. // It sets the adorned control's Height and Width to a hard-coded value. void autoSizeCheckBox_Unchecked(object sender, RoutedEventArgs e) { this.SetHeightAndWidth(false); } // The SetHeightAndWidth utility method sets the Height and Width // properties through the model and commits the change. private void SetHeightAndWidth(bool autoSize) { settingProperties = true; try { using (ModelEditingScope batchedChange = adornedControlModel.BeginEdit()) { ModelProperty widthProperty = adornedControlModel.Properties[Control.WidthProperty]; ModelProperty heightProperty = adornedControlModel.Properties[Control.HeightProperty]; if (autoSize) { widthProperty.ClearValue(); heightProperty.ClearValue(); } else { widthProperty.SetValue(20d); heightProperty.SetValue(20d); } batchedChange.Complete(); } } finally { settingProperties = false; } } // The following method deactivates the adorner. protected override void Deactivate() { adornedControlModel.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler( AdornedControlModel_PropertyChanged); base.Deactivate(); } // The following method handles the PropertyChanged event. void AdornedControlModel_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (settingProperties) { return; } if (e.PropertyName == "Height" || e.PropertyName == "Width") { double h = (double)adornedControlModel.Properties[Control.HeightProperty].ComputedValue; double w = (double)adornedControlModel.Properties[Control.WidthProperty].ComputedValue; autoSizeCheckBox.IsChecked = (h == double.NaN && w == double.NaN) ? true : false; } } } }
Выполните построение решения.
Тестирование реализации времени разработки
Элемент управления AutoSizeButton можно использовать как любой другой элемент управления WPF. WPF (конструктор) управляет созданием всех объектов времени разработки.
Тестирование реализации времени разработки
Добавьте к решению новый проект приложения WPF с именем DemoApplication.
В WPF (конструктор) откроется файл Window1.xaml.
Добавьте ссылку на проект AutoSizeButtonLibrary
В представлении XAML замените автоматически созданный код на следующий код. Этот код XAML добавляет ссылку на пространство имен AutoSizeButtonLibrary и пользовательский элемент управления AutoSizeButton. Кнопка появляется в представлении конструктора с текстом "Режим разработки активен", обозначающим включение режима разработки. Если кнопка не отображается, щелкните в панели информации в верхней части конструктора для перезагрузки представления.
<Window x:Class="DemoApplication.Window1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:ab="clr-namespace:AutoSizeButtonLibrary;assembly=AutoSizeButtonLibrary" Title="Window1" Height="300" Width="300"> <Grid> <ab:AutoSizeButton /> </Grid> </Window>
<Window x:Class="DemoApplication.Window1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:ab="clr-namespace:AutoSizeButtonLibrary;assembly=AutoSizeButtonLibrary" Title="Window1" Height="300" Width="300"> <Grid> <ab:AutoSizeButton Height="Auto" Width="Auto" /> </Grid> </Window>
В представлении конструктора выберите элемент управления AutoSizeButton.
Элемент управления CheckBox появится над элементом управления AutoSizeButton.
Снимите флажок с графического элемента.
Элемент управления уменьшается в размере. Графический элемент "флажок" перемещается для поддержания своего положения относительно элемента управления.
Настройка проекта для отладки во время разработки
На этом этапе реализация времени разработки завершена. Теперь можно использовать Visual Studio для задания точек останова и шага в коде времени разработки. Чтобы отладить реализацию времени разработки, следует присоединить другой экземпляр Visual Studio к текущему сеансу Visual Studio.
Настройка проекта для отладки во время разработки
В обозревателе решений щелкните правой кнопкой мыши проект DemoApplication и выберите Назначить запускаемым проектом.
В обозревателе решений щелкните правой кнопкой мыши проект DemoApplication и выберите Свойства.
В конструкторе проектов DemoApplication перейдите на вкладку Отладка.
В разделе Действие при запуске выберите Запуск внешней программы. Начнется отладка отдельного экземпляра Visual Studio.
Нажмите кнопку с многоточием () для открытия диалогового окна Выбор файла.
Найдите исполняемый файл Visual Studio. Имя этого исполняемого файла — devenv.exe, и, если программа Visual Studio установлена в папку по умолчанию, он находится в папке "%programfiles%\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe".
Нажмите кнопку Открыть, чтобы выбрать файл devenv.exe.
Отладка пользовательского элемента управления во время разработки
Теперь все готово для отладки пользовательского элемента управления в режиме разработки. При запуске сеанса отладки будет создан новый экземпляр Visual Studio, который будет использоваться для загрузки решения "AutoSizeButtonLibrary". При открытии файла Window1.xaml в WPF (конструктор) будет создан и запущен экземпляр пользовательского элемента управления.
Отладка пользовательского элемента управления во время разработки
Откройте файл с кодом AutoSizeButton в редакторе кода и добавьте точку останова в конструкторе.
Откройте файл Metadata.cs или Metadata.vb в редакторе кода и добавьте точку останова в методе Register.
Откройте файл AutoSizeAdornerProvider.cs или AutoSizeAdornerProvider.vb в редакторе кода и добавьте точку останова в конструкторе.
Добавьте точки останова в остальных методах класса AutoSizeAdornerProvider.
Нажмите клавишу F5 для запуска сеанса отладки.
Создается второй экземпляр Visual Studio. Экземпляр отладки и другой экземпляр можно различать двумя способами.
Экземпляр отладки имеет слово Выполняется в своем заголовке.
У экземпляра отладки выключена кнопка Запуск в панели инструментов Отладка.
Точка останова устанавливается в экземпляре отладки.
Откройте решение AutoSizeButtonLibrary во втором экземпляре Visual Studio.
Откройте файл Window1.xaml в WPF (конструктор).
Экземпляр отладки Visual Studio получает фокус и выполнение останавливает на точке останова Register.
Нажмите клавишу F5, чтобы продолжить отладку.
Выполнение останавливается в точке останова в конструкторе AutoSizeButton.
Нажмите клавишу F5, чтобы продолжить отладку.
Второй экземпляр Visual Studio получает фокус, отображается WPF (конструктор).
В представлении конструктора выберите элемент управления AutoSizeButton.
Экземпляр отладки Visual Studio получает фокус, и выполнение останавливается в точке останова в конструкторе AutoSizeAdornerProvider.
Нажмите клавишу F5, чтобы продолжить отладку.
Выполнение останавливается в точке останова в методе Activate.
Нажмите клавишу F5, чтобы продолжить отладку.
Второй экземпляр Visual Studio получает фокус, отображается WPF (конструктор). Графический элемент "флажок" отображается слева и вверху от элемента управления AutoSizeButton.
По завершении можно остановить сеанс отладки, закрыв второй экземпляр Visual Studio или нажав кнопку Остановить отладку в экземпляре отладки.
Следующие действия
Можно добавить дополнительные пользовательские функции времени разработки для пользовательских элементов управления.
Добавьте пользовательский графический элемент во время разработки элемента управления. Дополнительные сведения см. в разделе Пошаговое руководство. Создание графического элемента времени разработки.
Создайте редактор для пользовательского типа, который можно использовать в окне "Свойства". Дополнительные сведения см. в разделе Практическое руководство. Создание редактора значений.
Создайте редактор цвета, который можно использовать в окне "Свойства." Дополнительные сведения см. в разделе Пошаговое руководство. Реализация редактора цвета.
См. также
Ссылки
PrimarySelectionAdornerProvider