diff --git a/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs b/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs
new file mode 100644
index 0000000000..76bf1ca0ba
--- /dev/null
+++ b/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs
@@ -0,0 +1,35 @@
+// --------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+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");
+ }
+ }
+ }
+}
diff --git a/Perspex.Base/Diagnostics/PerspexPropertyValue.cs b/Perspex.Base/Diagnostics/PerspexPropertyValue.cs
index 7a4392f3b4..74f5cbf418 100644
--- a/Perspex.Base/Diagnostics/PerspexPropertyValue.cs
+++ b/Perspex.Base/Diagnostics/PerspexPropertyValue.cs
@@ -11,17 +11,21 @@ namespace Perspex.Diagnostics
public PerspexPropertyValue(
PerspexProperty property,
object value,
- BindingPriority priority)
+ BindingPriority priority,
+ string diagnostic)
{
this.Property = property;
this.Value = value;
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; }
}
}
diff --git a/Perspex.Base/Perspex.Base.csproj b/Perspex.Base/Perspex.Base.csproj
index cd618b7f8f..d23f3650cb 100644
--- a/Perspex.Base/Perspex.Base.csproj
+++ b/Perspex.Base/Perspex.Base.csproj
@@ -37,6 +37,7 @@
+
diff --git a/Perspex.Base/PerspexObject.cs b/Perspex.Base/PerspexObject.cs
index 69a504b1f5..04a369c84b 100644
--- a/Perspex.Base/PerspexObject.cs
+++ b/Perspex.Base/PerspexObject.cs
@@ -409,35 +409,6 @@ namespace Perspex
return (T)this.GetValue((PerspexProperty)property);
}
- ///
- /// Gets the value of of all properties that are registered on this object.
- ///
- ///
- /// A collection of objects.
- ///
- public IEnumerable 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);
- }
- }
- }
-
///
/// Gets all properties that are registered on this object.
///
@@ -464,20 +435,6 @@ namespace Perspex
}
}
- ///
- /// Gets all of the values explicitly set on this object.
- ///
- public IEnumerable GetSetValues()
- {
- foreach (var value in this.values)
- {
- yield return new PerspexPropertyValue(
- value.Key,
- value.Value.Value,
- (BindingPriority)value.Value.ValuePriority);
- }
- }
-
///
/// Checks whether a is set on this object.
///
@@ -681,6 +638,15 @@ namespace Perspex
}
}
+ ///
+ /// Gets all priority values set on the object.
+ ///
+ /// A collection of property/value tuples.
+ internal IDictionary GetSetValues()
+ {
+ return this.values;
+ }
+
///
/// Forces re-coercion of properties when a property value changes.
///
diff --git a/Perspex.Base/PerspexProperty.cs b/Perspex.Base/PerspexProperty.cs
index 9d41a8d1e9..c2eb1fb00d 100644
--- a/Perspex.Base/PerspexProperty.cs
+++ b/Perspex.Base/PerspexProperty.cs
@@ -361,7 +361,7 @@ namespace Perspex
{
public override string ToString()
{
- return "{Unset}";
+ return "(unset)";
}
}
}
diff --git a/Perspex.Base/PriorityValue.cs b/Perspex.Base/PriorityValue.cs
index 7ec0bdda01..b22ef91890 100644
--- a/Perspex.Base/PriorityValue.cs
+++ b/Perspex.Base/PriorityValue.cs
@@ -11,7 +11,7 @@ namespace Perspex
using System.Linq;
using System.Reactive.Subjects;
using System.Reflection;
- using Perspex.Diagnostics;
+ using System.Text;
///
/// Maintains a list of prioritised bindings together with a current value.
@@ -171,6 +171,46 @@ namespace Perspex
}
}
+ ///
+ /// Returns diagnostic string that can help the user debug the bindings in effect on
+ /// this object.
+ ///
+ /// A diagnostic string.
+ 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();
+ }
+
///
/// Causes a re-coercion of the value.
///
diff --git a/Perspex.Diagnostics/Debug.cs b/Perspex.Diagnostics/Debug.cs
index 27eea5fda0..ddf0716f15 100644
--- a/Perspex.Diagnostics/Debug.cs
+++ b/Perspex.Diagnostics/Debug.cs
@@ -40,16 +40,21 @@ namespace Perspex.Diagnostics
builder.Append(" ");
builder.AppendLine(control.Classes.ToString());
- foreach (var value in control.GetSetValues())
+ foreach (var property in control.GetRegisteredProperties())
{
- builder.Append(Indent(indent));
- builder.Append(" | ");
- builder.Append(value.Property.Name);
- builder.Append(" = ");
- builder.Append(value.Value ?? "(null)");
- builder.Append(" [");
- builder.Append(value.Priority);
- builder.AppendLine("]");
+ var value = control.GetDiagnostic(property);
+
+ if (value.Priority != BindingPriority.Unset)
+ {
+ builder.Append(Indent(indent));
+ builder.Append(" | ");
+ builder.Append(value.Property.Name);
+ builder.Append(" = ");
+ builder.Append(value.Value ?? "(null)");
+ builder.Append(" [");
+ builder.Append(value.Priority);
+ builder.AppendLine("]");
+ }
}
}
else
diff --git a/Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs b/Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs
index 25d22bd364..9d2e61157a 100644
--- a/Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs
+++ b/Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs
@@ -17,8 +17,8 @@ namespace Perspex.Diagnostics.ViewModels
{
if (control != null)
{
- this.Properties = control.GetAllValues()
- .Select(x => new PropertyDetails(x))
+ this.Properties = control.GetRegisteredProperties()
+ .Select(x => new PropertyDetails(control, x))
.OrderBy(x => x.Name)
.OrderBy(x => x.IsAttached);
}
diff --git a/Perspex.Diagnostics/ViewModels/PropertyDetails.cs b/Perspex.Diagnostics/ViewModels/PropertyDetails.cs
index c3570aa5c7..30b25faa57 100644
--- a/Perspex.Diagnostics/ViewModels/PropertyDetails.cs
+++ b/Perspex.Diagnostics/ViewModels/PropertyDetails.cs
@@ -13,32 +13,43 @@ namespace Perspex.Diagnostics.ViewModels
{
private object value;
- public PropertyDetails(PerspexPropertyValue value)
+ private string priority;
+
+ private string diagnostic;
+
+ public PropertyDetails(PerspexObject o, PerspexProperty property)
{
- this.Name = value.Property.IsAttached ?
- string.Format("[{0}.{1}]", value.Property.OwnerType.Name, value.Property.Name) :
- value.Property.Name;
- this.IsAttached = value.Property.IsAttached;
-
- this.value = value.Value ?? "(null)";
- this.Priority = (value.Priority != BindingPriority.Unset) ?
- value.Priority.ToString() :
- value.Property.Inherits ? "Inherited" : "Unset";
-
- //if (value.PriorityValue != null)
- //{
- // value.PriorityValue.Changed.Subscribe(x => this.Value = x.Item2);
- //}
+ this.Name = property.IsAttached ?
+ string.Format("[{0}.{1}]", property.OwnerType.Name, property.Name) :
+ property.Name;
+ this.IsAttached = property.IsAttached;
+
+ // TODO: Unsubscribe when view model is deactivated.
+ o.GetObservable(property).Subscribe(x =>
+ {
+ var diagnostic = o.GetDiagnostic(property);
+ this.Value = diagnostic.Value ?? "(null)";
+ this.Priority = (diagnostic.Priority != BindingPriority.Unset) ?
+ diagnostic.Priority.ToString() :
+ 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
@@ -46,11 +57,5 @@ namespace Perspex.Diagnostics.ViewModels
get { return this.value; }
private set { this.RaiseAndSetIfChanged(ref this.value, value); }
}
-
- public string Priority
- {
- get;
- private set;
- }
}
}
diff --git a/Perspex.Diagnostics/Views/ControlDetailsView.cs b/Perspex.Diagnostics/Views/ControlDetailsView.cs
index b3a05d4143..d73bd75ed7 100644
--- a/Perspex.Diagnostics/Views/ControlDetailsView.cs
+++ b/Perspex.Diagnostics/Views/ControlDetailsView.cs
@@ -55,7 +55,7 @@ namespace Perspex.Diagnostics.Views
{
new Setter(Control.MarginProperty, new Thickness(2)),
}
- }
+ },
},
[GridRepeater.TemplateProperty] = pt,
[!GridRepeater.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Properties),
@@ -69,7 +69,8 @@ namespace Perspex.Diagnostics.Views
yield return new TextBlock
{
- Text = property.Name
+ Text = property.Name,
+ [!ToolTip.TipProperty] = property.WhenAnyValue(x => x.Diagnostic),
};
yield return new TextBlock
@@ -77,7 +78,10 @@ namespace Perspex.Diagnostics.Views
[!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),
+ };
}
}
}