Как обнаружить нарушенную привязку данных WPF?


при попытке ответить на вопрос, в непосредственной близости ' модульное тестирование Привязок WPF

7 68

7 ответов:

в .NET 3.5 был введен новый способ специально выводить информацию трассировки о конкретных привязках данных.

Это делается через новый

лучшее, что я смог найти...

как я могу отлаживать привязки WPF? Беатрис Штольниц

поскольку все не всегда могут следить за окном вывода, ища ошибки привязки, мне понравился вариант № 2. То есть добавить это в свое приложение.Конфигурации

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.Windows.Data" switchName="SourceSwitch" >
        <listeners>
          <add name="textListener" />
        </listeners>
      </source>

    </sources>
      <switches>
        <add name="SourceSwitch" value="All" />
      </switches>

      <sharedListeners>
        <add name="textListener"
        type="System.Diagnostics.TextWriterTraceListener"
        initializeData="GraveOfBindErrors.txt" />
      </sharedListeners>

      <trace autoflush="true" indentsize="4"></trace>

  </system.diagnostics>
</configuration>

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

System.Windows.Data Error: 35 : BindingExpression path error: 'MyProperty' property not found on 'object' ''MyWindow' (Name='')'. BindingExpression:Path=MyProperty; DataItem='MyWindow' (Name=''); target element is 'TextBox' (Name='txtValue2'); target property is 'Text' (type 'String')

вы можете использовать функцию отладки триггера инспектора WPF. Просто загрузите инструмент из codeplex и прикрепите его к запущенному приложению. Это также показывает ошибки привязки в нижней части окна. Очень полезный инструмент!

enter image description here

Я использую решение, представленное здесь, чтобы превратить ошибки привязки в собственные исключения: http://www.jasonbock.net/jb/Default.aspx?blog=entry.0f221e047de740ee90722b248933a28d

однако обычный сценарий в привязках WPF заключается в создании исключений в случае, если пользовательский ввод не может быть преобразован в целевой тип (например, текстовое поле, привязанное к целочисленному полю; ввод нечисловой строки приводит к FormatException, вводу числа, которое является слишком большим результатом в OverflowException). Аналогичный случай имеет место, когда сеттер исходного свойства создает исключение.

способ обработки WPF это с помощью ValidatesOnExceptions=true и ValidationExceptionRule, чтобы сигнализировать пользователю, что предоставленный вход неверен (используя сообщение об исключении).

однако эти исключения также отправляются в окно вывода и, таким образом, "ловятся" BindingListener, что приводит к ошибке...явно не то поведение, которое вы бы хотеть.

поэтому я расширил BindingListener класс, чтобы не бросать исключение в этих случаях:

private static readonly IList<string> m_MessagesToIgnore =
        new List<String>()
        {
            //Windows.Data.Error 7
            //Binding transfer from target to source failed because of an exception
            //Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
            //To cope with these kind of errors
            "ConvertBack cannot convert value",

            //Windows.Data.Error 8
            //Binding transfer from target to source failed because of an exception
            //Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
            //To cope with these kind of errors
            "Cannot save value from target back to source"  
        };

измененные строки в public override void WriteLine (строковое сообщение):

        ....
        if (this.InformationPropertyCount == 0)
        {
            //Only treat message as an exception if it is not to be ignored
            if (!m_MessagesToIgnore.Any(
                x => this.Message.StartsWith(x, StringComparison.InvariantCultureIgnoreCase)))
            {
                PresentationTraceSources.DataBindingSource.Listeners.Remove(this);

                throw new BindingException(this.Message,
                    new BindingExceptionInformation(this.Callstack,
                        System.DateTime.Parse(this.DateTime),
                        this.LogicalOperationStack, int.Parse(this.ProcessId),
                        int.Parse(this.ThreadId), long.Parse(this.Timestamp)));
            }
            else
            {
                //Ignore message, reset values
                this.IsFirstWrite = true;
                this.DetermineInformationPropertyCount();
            }
        }
    }

вот полезный метод для отладки / трассировки триггеров эффективно. Она позволяет вести журнал всех действий с элементом воздействия:

http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html

Это было очень полезно для нас, но я хотел добавить к тем, кто считает это полезным, что есть утилита, которую Microsoft предоставляет с sdk для чтения этого файла.

найдено здесь:http://msdn.microsoft.com/en-us/library/ms732023.aspx

открыть файл трассировки

1.Запустите Средство просмотра трассировки службы с помощью командного окна для перехода к нужному Место установки WCF (C:\Program Файлы\Microsoft SDKs\Windows\v6. 0\Bin), а затем введите SvcTraceViewer.исполняемый. (хотя мы нашли наш в \v7. 0 \ Bin)

Примечание: средство просмотра трассировки службы можно связать с двумя типами файлов : .svclog и .stvproj все. Вы можете использовать два параметры в командной строке для регистрации и отмените регистрацию расширений файлов.

/ register: зарегистрировать ассоциацию расширение файла." svclog ПО" и ".stvproj " с SvcTraceViewer.exe

/unregister: отменить регистрацию ассоциация файлов увеличение ".svclog ПО" и ".stvproj " с SvcTraceViewer.exe

1.При запуске средства просмотра трассировки служб щелкните файл и выберите пункт Открыть. Перейдите к месту, где ваш файлы трассировки сохраняются.

2.Дважды щелкните файл трассировки, который требуется открыть.

Примечание: нажмите SHIFT при нажатии несколько файлов трассировки для выбора и откройте их одновременно. Услуга Средство просмотра трассировки объединяет содержимое всех файлы и представляет один вид. Для например, вы можете открыть файлы трассировки как клиент, так и сервис. Это полезно, когда вы включили сообщение ведение журнала и распространение активности в конфигурация. Таким образом, вы можете проверьте обмен сообщениями между клиент и обслуживание. Вы также можете перетащить несколько файлов в средстве просмотра, или использовать вкладка проект. См. раздел Управление Раздел проекта для получения более подробной информации.

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

кроме того, что касается фильтрации файла журнала, мы нашли эту ссылку чрезвычайно полезной:

http://msdn.microsoft.com/en-us/library/ms751526.aspx

для тех, кто, как я, ищет чистый программный способ включения всей трассировки WPF на заданном уровне трассировки, вот фрагмент кода, который это делает. Для справки, он основан на этой статье:источники трассировки в WPF.

это не требует изменения в приложение.конфигурационный файл, и он также не требует изменения реестра.

Это, как я использую его, в каком-то месте запуска (приложение, и т. д.):

....
#if DEBUG
    WpfUtilities.SetTracing();
#endif
....

а вот код утилиты (by по умолчанию он отправляет все предупреждения Прослушивателю трассировки по умолчанию):

public static void SetTracing()
{
    SetTracing(SourceLevels.Warning, null);
}

public static void SetTracing(SourceLevels levels, TraceListener listener)
{
    if (listener == null)
    {
        listener = new DefaultTraceListener();
    }

    // enable WPF tracing
    PresentationTraceSources.Refresh();

    // enable all WPF Trace sources (change this if you only want DataBindingSource)
    foreach (PropertyInfo pi in typeof(PresentationTraceSources).GetProperties(BindingFlags.Static | BindingFlags.Public))
    {
        if (typeof(TraceSource).IsAssignableFrom(pi.PropertyType))
        {
            TraceSource ts = (TraceSource)pi.GetValue(null, null);
            ts.Listeners.Add(listener);
            ts.Switch.Level = levels;
        }
    }
}