Browse Source

Added diagnostic popup to devtools.

pull/58/head
Steven Kirk 11 years ago
parent
commit
8d7d04ffd3
  1. 35
      Perspex.Base/Diagnostics/PerspexObjectExtensions.cs
  2. 12
      Perspex.Base/Diagnostics/PerspexPropertyValue.cs
  3. 1
      Perspex.Base/Perspex.Base.csproj
  4. 52
      Perspex.Base/PerspexObject.cs
  5. 2
      Perspex.Base/PerspexProperty.cs
  6. 42
      Perspex.Base/PriorityValue.cs
  7. 23
      Perspex.Diagnostics/Debug.cs
  8. 4
      Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs
  9. 55
      Perspex.Diagnostics/ViewModels/PropertyDetails.cs
  10. 10
      Perspex.Diagnostics/Views/ControlDetailsView.cs

35
Perspex.Base/Diagnostics/PerspexObjectExtensions.cs

@ -0,0 +1,35 @@
// --------------------------------------------------------------------
// <copyright file="PerspexObjectExtensions.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Diagnostics
{
public static class PerspexObjectExtensions
{
public static PerspexPropertyValue GetDiagnostic(this PerspexObject o, PerspexProperty property)
{
var set = o.GetSetValues();
PriorityValue value;
if (set.TryGetValue(property, out value))
{
return new PerspexPropertyValue(
property,
value.Value,
(BindingPriority)value.ValuePriority,
value.GetDiagnostic());
}
else
{
return new PerspexPropertyValue(
property,
o.GetValue(property),
BindingPriority.Unset,
"Unset");
}
}
}
}

12
Perspex.Base/Diagnostics/PerspexPropertyValue.cs

@ -11,17 +11,21 @@ namespace Perspex.Diagnostics
public PerspexPropertyValue( public PerspexPropertyValue(
PerspexProperty property, PerspexProperty property,
object value, object value,
BindingPriority priority) BindingPriority priority,
string diagnostic)
{ {
this.Property = property; this.Property = property;
this.Value = value; this.Value = value;
this.Priority = priority; this.Priority = priority;
this.Diagnostic = diagnostic;
} }
public PerspexProperty Property { get; private set; } public PerspexProperty Property { get; }
public object Value { get; private set; } public object Value { get; }
public BindingPriority Priority { get; private set; } public BindingPriority Priority { get; }
public string Diagnostic { get; }
} }
} }

1
Perspex.Base/Perspex.Base.csproj

@ -37,6 +37,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Binding.cs" /> <Compile Include="Binding.cs" />
<Compile Include="Diagnostics\PerspexObjectExtensions.cs" />
<Compile Include="PriorityBindingEntry.cs" /> <Compile Include="PriorityBindingEntry.cs" />
<Compile Include="Collections\IPerspexList.cs" /> <Compile Include="Collections\IPerspexList.cs" />
<Compile Include="Collections\PerspexReadOnlyListView.cs" /> <Compile Include="Collections\PerspexReadOnlyListView.cs" />

52
Perspex.Base/PerspexObject.cs

@ -409,35 +409,6 @@ namespace Perspex
return (T)this.GetValue((PerspexProperty)property); return (T)this.GetValue((PerspexProperty)property);
} }
/// <summary>
/// Gets the value of of all properties that are registered on this object.
/// </summary>
/// <returns>
/// A collection of <see cref="PerspexPropertyValue"/> objects.
/// </returns>
public IEnumerable<PerspexPropertyValue> GetAllValues()
{
foreach (PerspexProperty property in this.GetRegisteredProperties())
{
PriorityValue value;
if (this.values.TryGetValue(property, out value))
{
yield return new PerspexPropertyValue(
property,
value.Value,
(BindingPriority)value.ValuePriority);
}
else
{
yield return new PerspexPropertyValue(
property,
this.GetValue(property),
BindingPriority.Unset);
}
}
}
/// <summary> /// <summary>
/// Gets all properties that are registered on this object. /// Gets all properties that are registered on this object.
/// </summary> /// </summary>
@ -464,20 +435,6 @@ namespace Perspex
} }
} }
/// <summary>
/// Gets all of the <see cref="PerspexProperty"/> values explicitly set on this object.
/// </summary>
public IEnumerable<PerspexPropertyValue> GetSetValues()
{
foreach (var value in this.values)
{
yield return new PerspexPropertyValue(
value.Key,
value.Value.Value,
(BindingPriority)value.Value.ValuePriority);
}
}
/// <summary> /// <summary>
/// Checks whether a <see cref="PerspexProperty"/> is set on this object. /// Checks whether a <see cref="PerspexProperty"/> is set on this object.
/// </summary> /// </summary>
@ -681,6 +638,15 @@ namespace Perspex
} }
} }
/// <summary>
/// Gets all priority values set on the object.
/// </summary>
/// <returns>A collection of property/value tuples.</returns>
internal IDictionary<PerspexProperty, PriorityValue> GetSetValues()
{
return this.values;
}
/// <summary> /// <summary>
/// Forces re-coercion of properties when a property value changes. /// Forces re-coercion of properties when a property value changes.
/// </summary> /// </summary>

2
Perspex.Base/PerspexProperty.cs

@ -361,7 +361,7 @@ namespace Perspex
{ {
public override string ToString() public override string ToString()
{ {
return "{Unset}"; return "(unset)";
} }
} }
} }

42
Perspex.Base/PriorityValue.cs

@ -11,7 +11,7 @@ namespace Perspex
using System.Linq; using System.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Reflection; using System.Reflection;
using Perspex.Diagnostics; using System.Text;
/// <summary> /// <summary>
/// Maintains a list of prioritised bindings together with a current value. /// Maintains a list of prioritised bindings together with a current value.
@ -171,6 +171,46 @@ namespace Perspex
} }
} }
/// <summary>
/// Returns diagnostic string that can help the user debug the bindings in effect on
/// this object.
/// </summary>
/// <returns>A diagnostic string.</returns>
public string GetDiagnostic()
{
var b = new StringBuilder();
var first = true;
foreach (var level in this.levels)
{
if (!first)
{
b.AppendLine();
}
b.Append(this.ValuePriority == level.Key ? "*" : "");
b.Append("Priority ");
b.Append(level.Key);
b.Append(": ");
b.AppendLine(level.Value.Value?.ToString() ?? "(null)");
b.AppendLine("--------");
b.Append("Direct: ");
b.AppendLine(level.Value.DirectValue.ToString());
foreach (var binding in level.Value.Bindings)
{
b.Append(level.Value.ActiveBindingIndex == binding.Index ? "*" : "");
b.Append(binding.Description ?? binding.Observable.GetType().Name);
b.Append(": ");
b.AppendLine(binding.Value.ToString());
}
first = false;
}
return b.ToString();
}
/// <summary> /// <summary>
/// Causes a re-coercion of the value. /// Causes a re-coercion of the value.
/// </summary> /// </summary>

23
Perspex.Diagnostics/Debug.cs

@ -40,16 +40,21 @@ namespace Perspex.Diagnostics
builder.Append(" "); builder.Append(" ");
builder.AppendLine(control.Classes.ToString()); builder.AppendLine(control.Classes.ToString());
foreach (var value in control.GetSetValues()) foreach (var property in control.GetRegisteredProperties())
{ {
builder.Append(Indent(indent)); var value = control.GetDiagnostic(property);
builder.Append(" | ");
builder.Append(value.Property.Name); if (value.Priority != BindingPriority.Unset)
builder.Append(" = "); {
builder.Append(value.Value ?? "(null)"); builder.Append(Indent(indent));
builder.Append(" ["); builder.Append(" | ");
builder.Append(value.Priority); builder.Append(value.Property.Name);
builder.AppendLine("]"); builder.Append(" = ");
builder.Append(value.Value ?? "(null)");
builder.Append(" [");
builder.Append(value.Priority);
builder.AppendLine("]");
}
} }
} }
else else

4
Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs

@ -17,8 +17,8 @@ namespace Perspex.Diagnostics.ViewModels
{ {
if (control != null) if (control != null)
{ {
this.Properties = control.GetAllValues() this.Properties = control.GetRegisteredProperties()
.Select(x => new PropertyDetails(x)) .Select(x => new PropertyDetails(control, x))
.OrderBy(x => x.Name) .OrderBy(x => x.Name)
.OrderBy(x => x.IsAttached); .OrderBy(x => x.IsAttached);
} }

55
Perspex.Diagnostics/ViewModels/PropertyDetails.cs

@ -13,32 +13,43 @@ namespace Perspex.Diagnostics.ViewModels
{ {
private object value; private object value;
public PropertyDetails(PerspexPropertyValue value) private string priority;
private string diagnostic;
public PropertyDetails(PerspexObject o, PerspexProperty property)
{ {
this.Name = value.Property.IsAttached ? this.Name = property.IsAttached ?
string.Format("[{0}.{1}]", value.Property.OwnerType.Name, value.Property.Name) : string.Format("[{0}.{1}]", property.OwnerType.Name, property.Name) :
value.Property.Name; property.Name;
this.IsAttached = value.Property.IsAttached; this.IsAttached = property.IsAttached;
this.value = value.Value ?? "(null)"; // TODO: Unsubscribe when view model is deactivated.
this.Priority = (value.Priority != BindingPriority.Unset) ? o.GetObservable(property).Subscribe(x =>
value.Priority.ToString() : {
value.Property.Inherits ? "Inherited" : "Unset"; var diagnostic = o.GetDiagnostic(property);
this.Value = diagnostic.Value ?? "(null)";
//if (value.PriorityValue != null) this.Priority = (diagnostic.Priority != BindingPriority.Unset) ?
//{ diagnostic.Priority.ToString() :
// value.PriorityValue.Changed.Subscribe(x => this.Value = x.Item2); diagnostic.Property.Inherits ? "Inherited" : "Unset";
//} this.Diagnostic = diagnostic.Diagnostic;
});
} }
public string Name public string Name { get; }
public bool IsAttached { get; }
public string Priority
{ {
get; get { return this.priority; }
private set { this.RaiseAndSetIfChanged(ref this.priority, value); }
} }
public bool IsAttached public string Diagnostic
{ {
get; get { return this.diagnostic; }
private set { this.RaiseAndSetIfChanged(ref this.diagnostic, value); }
} }
public object Value public object Value
@ -46,11 +57,5 @@ namespace Perspex.Diagnostics.ViewModels
get { return this.value; } get { return this.value; }
private set { this.RaiseAndSetIfChanged(ref this.value, value); } private set { this.RaiseAndSetIfChanged(ref this.value, value); }
} }
public string Priority
{
get;
private set;
}
} }
} }

10
Perspex.Diagnostics/Views/ControlDetailsView.cs

@ -55,7 +55,7 @@ namespace Perspex.Diagnostics.Views
{ {
new Setter(Control.MarginProperty, new Thickness(2)), new Setter(Control.MarginProperty, new Thickness(2)),
} }
} },
}, },
[GridRepeater.TemplateProperty] = pt, [GridRepeater.TemplateProperty] = pt,
[!GridRepeater.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Properties), [!GridRepeater.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Properties),
@ -69,7 +69,8 @@ namespace Perspex.Diagnostics.Views
yield return new TextBlock yield return new TextBlock
{ {
Text = property.Name Text = property.Name,
[!ToolTip.TipProperty] = property.WhenAnyValue(x => x.Diagnostic),
}; };
yield return new TextBlock yield return new TextBlock
@ -77,7 +78,10 @@ namespace Perspex.Diagnostics.Views
[!TextBlock.TextProperty] = property.WhenAnyValue(v => v.Value).Select(v => v?.ToString()), [!TextBlock.TextProperty] = property.WhenAnyValue(v => v.Value).Select(v => v?.ToString()),
}; };
yield return new TextBlock { Text = property.Priority }; yield return new TextBlock
{
[!TextBlock.TextProperty] = property.WhenAnyValue(x => x.Priority),
};
} }
} }
} }

Loading…
Cancel
Save