Поделиться через


Разрешение вопросов, связанных с ошибками загрузки конструктора WPF

Обновлен: Ноябрь 2007

Windows Presentation Foundation (WPF) для Visual Studio (конструктор) включает многофункциональный и расширяемый визуальный конструктор для создания XAML-кода. Если XAML-файл не загружается в конструктор, есть несколько вариантов устранения неполадок. В этом разделе приводятся некоторые советы и описываются способы, позволяющие устранить ошибки загрузки WPF (конструктор).

Bb546934.alert_note(ru-ru,VS.90).gifПримечание.

Многие из способов, описанных в этом разделе, также применимы к средству Expression Blend.

Этапы устранения неполадок

Следующие действия помогут устранить ошибки загрузки WPF (конструктор).

  1. Прочитайте все полученные сообщения об исключениях.

    Это может казаться очевидным, но в случае получения исключения следует внимательно прочитать сообщение. В некоторых случаях это помогает быстро найти причину проблемы. Дополнительные сведения см. в разделе Отладка и интерпретация ошибок в конструкторе WPF.

  2. Определите, не обусловлена ли проблема конкретной реализацией.

    Создайте и запустите приложение, чтобы определить является ли неполадка результатом только реализации или взаимодействия с WPF (конструктор). Если приложение строится и запускается, ошибка времени разработки скорее всего вызвана реализацией.

  3. Используйте отладчик Visual Studio для перехода в код во время разработки. Дополнительные сведения см. в разделе Пошаговое руководство. Отладка пользовательских элементов управления WPF во время разработки.

  4. Определите, является ли проблемой ошибка загрузки.

    Если конструктору не удается выполнить загрузку из-за возникновения исключения, проблемой, скорее всего, является ошибка загрузки. Если имеется пользовательский код, который загружается во время разработки, и во время разработки возникают исключения или ошибки загрузки, см. раздел Написание кода для времени разработки ниже. Если при работе с ресурсами они не загружаются, см. раздел UserControl и ресурсы настраиваемых элементов управления во время разработки ниже.

  5. Просмотрите код, который загружается во время разработки.

    Существует два подхода к записи кода, который также выполняется во время разработки. Первый подход заключается в написании защитного кода путем проверки входных параметров для классов. Второй подход заключается в проверке активности режима разработки вызовом метода GetIsInDesignMode. Дополнительные сведения см. в разделе Написание кода для времени разработки ниже.

  6. Просмотрите другие области кода.

    Некоторые советы по программированию при работе с WPF (конструктор) содержатся в разделе Советы про программированию ниже. Методы написания наиболее надежного кода см. в разделе Рекомендации по программированию ниже.

  7. Если проблемы остаются, можно перейти на форум разработчиков WPF на MSDN (на английском языке), чтобы связаться с другими разработчиками, использующими WPF (конструктор). Для отправки отчета о вероятных проблемах и возможных предложений воспользуйтесь веб-узлом Visual Studio и .NET Framework. Feedback (на английском языке).

Написание кода для времени разработки

Убедитесь, что код выполняется как во время разработки, так и во время выполнения. Если код выполняется во время разработки, не следует полагать, что Application.Current является разрабатываемым приложением. Например, при использовании средства Expression Blend Current является Expression Blend. Во время разработки MainWindow не является главным окном разрабатываемого приложения. К типичным операциям, вызывающим сбой настраиваемого элемента управления во время разработки, относятся:

  • приведение типа Current к настраиваемым подклассам Application,

  • приведение типа MainWindow к настраиваемым подклассам Window,

  • использование метода FindResource или FindName на Current или MainWindow,

  • создание ссылок на ресурсы из Application.Resources. Экземпляр времени разработки Application отличается от разрабатываемого приложения и имеет другие ресурсы,

  • отсутствие проверки возвращения методом Application.Current или Application.MainWindow значения null. Если Visual Studio не создает объект приложения, то Application.Current может возвращать значение null,

  • отсутствие проверки возвращения методом Assembly.GetEntryAssembly значения null. Для среды Visual Studio этот метод возвращает значение null.

Существует два подхода к написанию кода для времени разработки. Первый подход заключается в написании защитного кода путем проверки входных параметров классов, таких как преобразователи значений. Второй подход заключается в проверке активности режима разработки вызовом метода GetIsInDesignMode.

Проверка входных параметров необходима для некоторых реализаций, так как для некоторых входных данных среда разработки предоставляет типы, отличающиеся от тех, что предоставляет среда выполнения.

Обычно, для селекторов стиля и преобразователей значений требуется один из этих подходов для правильной работы во время разработки.

Преобразователи значений

В пользовательской реализации IValueConverter должна проводиться проверка на наличие значения null и на ожидаемый тип первого параметра метода Convert. В следующем XAML-коде показывается привязка к Application.Current, которая во время разработки приводит к сбою, если преобразователь значений реализован неверно.

<ComboBox.IsEnabled>
    <MultiBinding Converter="{StaticResource specialFeaturesConverter}">
        <Binding Path="CurrentUser.Rating" Source="{x:Static Application.Current}"/>
        <Binding Path="CurrentUser.MemberSince" Source="{x:Static Application.Current}"/>
    </MultiBinding>
</ComboBox.IsEnabled>

Привязка вызывает исключение во время разработки, так как Application.Current ссылается на приложение конструктора вместо разрабатываемого приложения. Чтобы избежать возникновения исключения, преобразователь значений должен проверять свои входные параметры или активность режима разработки.

В следующем примере кода показывается, как проверять входные параметры в преобразователе значений, возвращающем значение true, если два входных параметра удовлетворяют конкретной бизнес-логике.

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    // Check the values array for correct parameters.
    // Designers may send null or unexpected values.
    if (values == null || values.Length < 2) return false;
    if (!(values[0] is int)) return false;
    if (!(values[1] is DateTime)) return false;

    int rating = (int)values[0];
    DateTime date = (DateTime)values[1];

    // If the user has a good rating (10+) and has been a member for 
    // more than a year, special features are available.
    if((rating >= 10) && 
        (date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
    {
        return true;
    }
    return false;
}

Второй подход к написанию кода для времени разработки заключается в проверке активности режима разработки. В следующем примере показывается проверка активности режима разработки вместо проверки параметров, показанной ранее.

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    // Check for design mode. 
    if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)) 
    {
        return false;
    }

    int rating = (int)values[0];
    DateTime date = (DateTime)values[1];

    // If the user has a good rating (10+) and has been a member for 
    // more than a year, special features are available.
    if((rating >= 10) && 
        (date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
    {
        return true;
    }
    return false;
}

Селекторы стиля

Настраиваемые селекторы стиля также должны быть реализованы для запуска в режиме разработки. В следующем XAML-коде показан настраиваемый селектор шаблона, в котором во время выполнения используется свойство Application.MainWindow для определения ресурса, возвращаемого в виде DataTemplate. Во время разработки этот ресурс может быть недоступен, поэтому перегрузка SelectTemplate возвращает значение null во время разработки.

<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>
<ListBox Width="400" Margin="10"
    ItemsSource="{Binding Source={StaticResource myTodoList}}"
    ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
    HorizontalContentAlignment="Stretch" 
    IsSynchronizedWithCurrentItem="True"/>

В следующем коде показывается реализация селектора стиля.

public class TaskListDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(
        object item, 
        DependencyObject container)
    {
        if (item != null && item is Task)
        {
            Task taskitem = item as Task;
            Window window = Application.Current.MainWindow;

            // To run in design mode, either test for the correct window class
            // or test for design mode.
            if (window.GetType() == typeof(Window1))
            // Or check for design mode: 
            //if (!DesignerProperties.GetIsInDesignMode(window))
            {
                if (taskitem.Priority == 1)
                return window.FindResource("importantTaskTemplate") as DataTemplate;
                else
                return window.FindResource("myTaskTemplate") as DataTemplate;
            }
        }
        return null;
    }
}

UserControl и ресурсы настраиваемых элементов управления во время разработки

По умолчанию UserControl и ресурсы настраиваемых элементов управления, доступные во время выполнения, могут быть недоступны во время разработки. При добавлении настраиваемых элементов управления и пользовательских элементов управления в Page или Window в области конструктора создается экземпляр элемента управления. Ресурсы в файле App.xaml недоступны для UserControl и экземпляров настраиваемых элементов управления, загруженных на страницу или в окно.

Чтобы ресурсы были доступны во время разработки, добавьте их в отдельный словарь ресурсов и включите словарь в файл App.xaml и XAML-код элемента управления. Измените все ссылки StaticResource на ссылки DynamicResource. В следующем примере показано, как сделать словарь ресурсов общим, чтобы его ресурсы были доступны во время разработки.

UserControl1.xaml

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

App.xaml

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Синтаксис Pack URI

Не следует использовать ссылки на ресурсы, локальные для приложений. В следующем примере кода показан синтаксис для приложения, который может вызвать сбой во время разработки.

<Image Name="image1" Source="pack://application:,,,/Image1.bmp" />

Такие ссылки относятся к приложению, а не к DLL-библиотеке. Использование ссылки на ресурс, локальной относительно приложения, в DLL-библиотеке файле делает DLL-библиотеку зависимой от ресурсов родительского приложения. Такой метод не обеспечивает достаточной надежности и не гарантирует работоспособности во время разработки.

Вместо использования ссылок на ресурсы, относящихся к приложению, добавьте ресурсы непосредственно в DLL-библиотеку и используйте ссылки на ресурсы на основе компонента. Дополнительные сведения см. в разделе URI типа "pack" в Windows Presentation Foundation.

В следующем примере кода показан синтаксис на основе компонента, который рекомендуется к применению.

<Image Name="image1" Source="/TestHostApp;component/Image1.bmp" />
<Image Name="image1" Source="pack://application:,,,/TestHostApp;component/Image1

Советы по программированию

Ниже приведены некоторые советы по программированию при работе с WPF (конструктор).

  • Если требуется загрузить пользовательский элемент управления в WPF (конструктор), необходимо указать методы получения и установки среды CLR для всех определяемых свойств зависимостей. Дополнительные сведения см. в разделе Пользовательские свойства зависимостей.

  • Графические элементы типа ComboBox не поддерживаются.

  • Чтобы использовать сторонний элемент управления Windows Forms, создайте тип UserControl, у которого есть экземпляр элемента управления от стороннего производителя в своей коллекции Controls. Дополнительные сведения см. в разделе Пошаговое руководство. Размещение стороннего элемента управления Windows Forms в приложении WPF.

  • Время разработки для FlowDocument непосредственно не поддерживается. Если требуется использовать WPF (конструктор) для встроенного FlowDocument, сначала поместите FlowDocument в элемент управления Frame, который затем можно использовать в WPF (конструктор).

Рекомендации по программированию

Ниже приведены некоторые рекомендации по программированию, позволяющие создавать более надежный код для WPF (конструктор).

  • Всегда заключайте области изменения в операторы using или блоки try/finally. Если возникает исключение, изменение прерывается в вызове Dispose. Дополнительные сведения см. в разделе ModelEditingScope.

  • Для перемещения элемента управления из одного контейнера в другой используйте метод ModelEditingScope. Если этого не сделать, то возникнет исключение.

  • В WPF и WPF (конструктор) не задавайте значение свойства по умолчанию, если планируется его очистка. Для значений NaN таких, как Height следует вызвать метод ClearValue вместо присваивания NaN.

  • При извлечении значений из свойства, используйте вычисляемое значение свойства. Это означает, что следует использовать свойство ComputedValue вместо метода GetCurrentValue модели ModelItem. Метод GetCurrentValue возвращает привязки и другие выражения, если они были сохранены в XAML-файле, поэтому в некоторых случаях могут возникать исключения при приведении типов.

См. также

Другие ресурсы

Отладка и интерпретация ошибок в конструкторе WPF

Примеры использования XAML и кода

Основные понятия расширяемости

Общее представление о расширяемости конструктора WPF