Другое

Полное руководство по исправлению ошибок привязки Uri в WPF

Узнайте, как идентифицировать и устранять ошибки привязки 'Cannot convert from type '<null>' to type 'System.Uri'' в крупных приложениях WPF. Полные стратегии отладки и практические решения.

Как идентифицировать и устранить ошибки привязки “Cannot convert from type ‘’ to type ‘System.Uri’” в приложениях WPF?

Я работаю над приложением C# WPF с примерно 170 проектами и многочисленными файлами XAML. При запуске приложения через Visual Studio я сталкиваюсь с тремя ошибками привязки XAML со следующим сообщением:

Cannot convert '<null>' from type '<null>' to type 'System.Uri' for 'de-DE' culture with default conversions; consider using Converter property of Binding.
NotSupportedException: System.NotSupportedException: UriTypeConverter cannot convert from (null).

Ошибка возникает три раза, но не предоставляет информации о местоположении проблемы. Я искал по всему решению “Uri”, “NavigateUri” или “Url”, но не смог определить, где возникает эта проблема. Похоже, это специфическая проблема WPF, поскольку установка точек останова в Exception Settings для NotSupportedException не дала полезных результатов.

Кроме того, у моей команды нет информации о том, какие ссылки должны присутствовать, что затрудняет идентификацию сломанных ссылок.

Вывод отладки показывает следующее предупреждение:

System.Windows.Data Error: 23 : Cannot convert '<null>' from type '<null>' to type 'System.Uri' for 'de-DE' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: UriTypeConverter cannot convert from (null).
   at System.ComponentModel.TypeConverter.GetConvertFromException(Object value)
   at System.UriTypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   at MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)'

Какие стратегии можно использовать для определения источника этих сбоев привязки и их устранения?

Ошибка привязки “Не удалось преобразовать из типа ‘’ в тип ‘System.Uri’” возникает, когда WPF пытается привязать значение null к свойству типа System.Uri, например, к NavigateUri в элементах Hyperlink, но UriTypeConverter не может обрабатывать значения null. Это распространенная проблема в крупных приложениях WPF, где в модели данных могут присутствовать значения null, а свойство Uri ожидает корректный URI.

Содержание


Понимание основной причины

Ошибка возникает потому, что NavigateUri и аналогичные свойства на основе Uri требуют корректного объекта System.Uri, но ваша привязка предоставляет значения null или пустые строки. Как объясняется на Microsoft Learn, это происходит, когда:

xml
<Hyperlink NavigateUri="{Binding SomeUriProperty}" />

Где SomeUriProperty возвращает null, пустую строку или строку с пробелами. UriTypeConverter не может преобразовать эти значения в корректный объект Uri.

Распространенные сценарии включают:

  • Привязки адресов электронной почты (mailto:)
  • Пути к файлам
  • Веб-URL в вашей модели данных
  • Поля базы данных, которые могут быть null
  • Параметры конфигурации, которые не были правильно инициализированы

Стратегии отладки для поиска проблемы

При наличии 170 проектов и множества XAML-файлов вам нужны систематические подходы для поиска проблемных привязок.

Включение диагностики привязок WPF

Сначала убедитесь, что ошибки привязок WPF логируются:

  1. Параметры Visual Studio: Перейдите в Инструменты → Параметры → Отладка → Окно вывода → Параметры трассировки WPF и установите уровень Предупреждение или Подробный
  2. Пользовательский прослушиватель трассировки: Реализируйте трассировщик ошибок привязки, как показано в этом решении на Stack Overflow solution
csharp
using System.Diagnostics;
using System.Windows;

public static class BindingDebugHelper
{
    public static void EnableBindingErrorTracing()
    {
        PresentationTraceSources.DataBindingSource.Listeners.Add(
            new ConsoleTraceListener()
        );
        PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Warning;
    }
}

// Вызовите это в конструкторе вашего App.xaml.cs
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        BindingDebugHelper.EnableBindingErrorTracing();
        base.OnStartup(e);
    }
}

Трассировка презентации

Добавьте PresentationTraceSources.TraceLevelProperty="High" к вашим привязкам:

xml
<Hyperlink NavigateUri="{Binding SomeUri, PresentationTraceSources.TraceLevel=High}" />

Это предоставит подробную информацию о пути привязки и источнике в отладочном выводе.

Анализ окна вывода

Следите за этими паттернами в окне вывода:

System.Windows.Data Error: 23 : Cannot convert '<null>' from type '<null>' to type 'System.Uri'...
BindingExpression:Path=YourProperty; DataItem=YourDataContext; target element is 'Hyperlink'...

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


Подходы к решению

Метод 1: Использование преобразователя значений

Создайте StringToUriConverter, который корректно обрабатывает значения null:

csharp
public class StringToUriConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return new Uri("about:blank", UriKind.RelativeOrAbsolute);
        
        if (string.IsNullOrWhiteSpace(value.ToString()))
            return new Uri("about:blank", UriKind.RelativeOrAbsolute);
            
        try
        {
            return new Uri(value.ToString(), UriKind.RelativeOrAbsolute);
        }
        catch
        {
            return new Uri("about:blank", UriKind.RelativeOrAbsolute);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Uri uri)
            return uri.ToString();
        return null;
    }
}

Используйте его в вашем XAML:

xml
<Hyperlink NavigateUri="{Binding SomeUri, Converter={StaticResource StringToUriConverter}}" />

Метод 2: Обработка null в ViewModel

Убедитесь, что ваши свойства никогда не возвращают null:

csharp
public string SomeUrl
{
    get => _someUrl ?? string.Empty;
    set => _someUrl = value;
}

Метод 3: Использование резервных значений

Предоставьте резервные значения в вашей привязке:

xml
<Hyperlink NavigateUri="{Binding SomeUri, FallbackValue=about:blank}" />

Метод 4: MultiBinding с StringFormat

Для сложного построения URI:

xml
<Hyperlink NavigateUri="">
    <Hyperlink.NavigateUri>
        <MultiBinding Converter="{StaticResource UriConverter}">
            <Binding Path="BaseUrl" />
            <Binding Path="Path" />
            <Binding Path="QueryParams" />
        </MultiBinding>
    </Hyperlink.NavigateUri>
</Hyperlink>

Профилактические меры

Валидация данных

Добавьте валидацию в ваши viewmodels:

csharp
public class UriValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
            return new ValidationResult(false, "URI не может быть пустым");
            
        try
        {
            new Uri(value.ToString(), UriKind.RelativeOrAbsolute);
            return ValidationResult.ValidResult;
        }
        catch
        {
            return new ValidationResult(false, "Неверный формат URI");
        }
    }
}

Шаблон Null Object

Рассмотрите реализацию шаблона null object для URI:

csharp
public static class UriExtensions
{
    public static Uri OrEmpty(this Uri uri)
    {
        return uri ?? new Uri("about:blank", UriKind.RelativeOrAbsolute);
    }
}

Правила анализа кода

Создайте пользовательские правила анализа кода для обнаружения проблемных привязок URI:

csharp
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class UriBindingAnalyzer : DiagnosticAnalyzer
{
    // Реализация для обнаружения привязок URI, склонных к null
}

Расширенная диагностика

Точки остановки на привязках

Установите условные точки остановки на UriTypeConverter:

csharp
// В вашем преобразователе или пользовательской логике привязки
if (value == null)
{
    Debugger.Break();
}

Инструменты профилирования

Используйте инструменты профилирования производительности WPF для отслеживания операций привязки:

xml
<Hyperlink NavigateUri="{Binding SomeUri, diag:PresentationTraceSources.TraceLevel=High}" 
          xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"/>

Систематический поиск

Создайте утилиту для сканирования всех XAML-файлов на предмет проблемных паттернов:

csharp
public static class UriBindingScanner
{
    public static void ScanAllXamlFiles(string solutionPath)
    {
        var xamlFiles = Directory.GetFiles(solutionPath, "*.xaml", SearchOption.AllDirectories);
        
        foreach (var file in xamlFiles)
        {
            var content = File.ReadAllText(file);
            if (content.Contains("NavigateUri") && content.Contains("{Binding"))
            {
                // Проверка на потенциальные проблемы с null
                Console.WriteLine($"Потенциальная проблема в: {file}");
            }
        }
    }
}

Реализовав эти стратегии, вы сможете идентифицировать и устранить ошибки преобразования null-to-Uri в вашем большом приложении WPF. Начните с подходов к отладке для точного определения привязок, вызывающих проблемы, затем примените соответствующий метод решения в зависимости от вашего конкретного случая использования.

Источники

  1. Диагностика привязок данных XAML - Microsoft Learn
  2. Как найти источник ошибки привязки - Stack Overflow
  3. Отладка привязок данных - WPF Tutorial
  4. WPF - Cannot convert ’ ’ from type ’ ’ to type ‘System.Uri’ - iTecNote
  5. Getting a warning when using a value converter trying to assign a Uri - MSDN Forums

Заключение

Для обобщения ключевых стратегий решения ошибок преобразования null-to-Uri:

  1. Включите комплексную диагностику привязок с использованием параметров трассировки WPF и пользовательских прослушивателей для получения подробной информации об ошибках
  2. Используйте трассировку презентации для проблемных привязок для точного определения местоположения источника
  3. Реализуйте надежные преобразователи значений, которые корректно обрабатывают значения null с резервными URI
  4. Добавьте правильную валидацию в ваши viewmodels для предотвращения попадания значений null в пользовательский интерфейс
  5. Создайте систематические утилиты поиска для сканирования вашей большой кодовой базы на предмет потенциальных проблемных привязок

Для вашей конкретной ситуации с 170 проектами начните с включения диагностики привязок и трассировки презентации для получения точных местоположений проблемных привязок. После их определения примените соответствующий метод решения - преобразователи значений часто являются наиболее практичным решением для существующих кодовых баз. Рассмотрите возможность реализации профилактических мер, таких как правила валидации, для избежания подобных проблем в будущем.

Авторы
Проверено модерацией
Модерация