AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
26.09k stars 2.26k forks source link

DataContext value in DevTools displayed as null if type of value inherited from System.ComponentModel.Component #15877

Open BreakByBrick opened 6 months ago

BreakByBrick commented 6 months ago

Describe the bug

Hello!

When ViewModel is inherited from System.ComponentModel.Component, it displays in DataContext value of DevTools.

image

But in debug DataContext has value.

image

image

To Reproduce

https://github.com/BreakByBrick/Avalonia.Issue/tree/main/DevTools.DataContextWithComponentDisplaysNull

image

Expected behavior

The DataContext value in DevTools must not be null.

Avalonia version

11.0.10

OS

Windows

Additional context

No response

stevemonaco commented 6 months ago

The type to text ultimately goes through: https://github.com/AvaloniaUI/Avalonia/blob/9be975b0e4874bc5d1cad4872615db40959a2430/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs#L345-L355

Component has a .NET type, ComponentConverter, that is being used to ConvertToInvariantString(...) which goes through ConvertTo in this case. Component and string aren't really convertible, so it returns null.

So the fix is probably to add another special case to the if so the type name is returned:

if (!converter.CanConvertTo(typeof(string)) ||
    converter.GetType() == typeof(CollectionConverter) ||
    converter.GetType() == typeof(ComponentConverter))
    return o.ToString();

I can PR if this seems reasonable to a maintainer. I'm not familiar with Component at all. ie. Should we force the type string to be returned or can/should the app dev write a custom+default implementation?

jp2masa commented 6 months ago

Maybe it should just fallback to o.ToString()?

return converter.ConvertToInvariantString(o) ?? o.ToString();

or

if (!converter.CanConvertTo(typeof(string)) ||
    converter.GetType() == typeof(CollectionConverter) ||
    converter.ConvertToInvariantString(o) is not { } converted)
    return o.ToString();

return converted;
stevemonaco commented 6 months ago

I misdiagnosed because this is a bit nonsensical. converter.ConvertToInvariantString(o) for ComponentConverter actually returns an empty string after double-checking, so null fallback won't work. DevTools then somewhere along the line interprets this as (null) and I don't yet understand how/where.

Even simpler, you can repro with <TextBlock Text="" />, on 11.0.10 and nightly. The DevTools display will be (null).

Explicit ComponentConverter check might still be necessary?