Skip to content

Instantly share code, notes, and snippets.

@ChadSki
Last active August 29, 2015 14:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChadSki/e8af798636e9096e95fb to your computer and use it in GitHub Desktop.
Save ChadSki/e8af798636e9096e95fb to your computer and use it in GitHub Desktop.
Databinding to Dynamic Objects?
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using Quickbeam.Low;
namespace MetroIde.Controls.MetaEditor
{
public class FieldControlSelector : DataTemplateSelector
{
private static readonly Dictionary<Type, string> DataTemplateKeys = new Dictionary<Type, string>
{
/* Signed ints */
{typeof (SByte), "Int8FieldTemplate"},
{typeof (Int16), "Int16FieldTemplate"},
{typeof (Int32), "Int32FieldTemplate"},
{typeof (Int64), "Int64FieldTemplate"},
/* Unsigned ints */
{typeof (Byte), "UInt8FieldTemplate"},
{typeof (UInt16), "UInt16FieldTemplate"},
{typeof (UInt32), "UInt32FieldTemplate"},
{typeof (UInt64), "UInt64FieldTemplate"},
/* Floating-point */
{typeof (Single), "Float32FieldTemplate"},
{typeof (Double), "Float64FieldTemplate"},
/* String */
{typeof (String), "StringFieldTemplate"},
/* Reflexive */
{typeof (IEnumerable<ObservableObject>), "ReflexiveFieldTemplate"},
};
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var o = item as ObservableAttribute<dynamic>;
if (o == null)
return null;
var key = DataTemplateKeys[o.Value.GetType()];
return Application.Current.Resources[key] as DataTemplate;
}
}
}
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:low="clr-namespace:Quickbeam.Low;assembly=Quickbeam.Low">
<!-- Integers -->
<DataTemplate x:Key="Int8FieldTemplate">
<TextBlock Text="{Binding Path=(low:Int8Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="Int16FieldTemplate">
<TextBlock Text="{Binding Path=(low:Int16Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="Int32FieldTemplate">
<TextBlock Text="{Binding Path=(low:Int32Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="Int64FieldTemplate">
<TextBlock Text="{Binding Path=(low:Int64Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="UInt8FieldTemplate">
<TextBlock Text="{Binding Path=(low:UInt8Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="UInt16FieldTemplate">
<TextBlock Text="{Binding Path=(low:UInt16Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="UInt32FieldTemplate">
<TextBlock Text="{Binding Path=(low:UInt32Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="UInt64FieldTemplate">
<TextBlock Text="{Binding Path=(low:UInt64Attribute.Value)}"/>
</DataTemplate>
<!-- Floating-point -->
<DataTemplate x:Key="Float32FieldTemplate">
<TextBlock Text="{Binding Path=(low:Float32Attribute.Value)}"/>
</DataTemplate>
<DataTemplate x:Key="Float64FieldTemplate">
<TextBlock Text="{Binding Path=(low:Float64Attribute.Value)}"/>
</DataTemplate>
<!-- String -->
<DataTemplate x:Key="StringFieldTemplate">
<TextBlock Text="{Binding Path=(low:StringAttribute.Value)}"/>
</DataTemplate>
<!-- Reflexive -->
<DataTemplate x:Key="ReflexiveFieldTemplate">
<TextBlock Text="{Binding Path=(low:ReflexiveAttribute.Value)}"/>
</DataTemplate>
</ResourceDictionary>
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Quickbeam.Low.Annotations;
namespace Quickbeam.Low
{
/// <summary>
/// An observable collection of observable attributes. This object fires
/// ICollectionChanged events when attributes are added or removed, and the
/// attributes themselves provide INotifyPropertyChanged events.
/// </summary>
public class ObservableObject : ObservableCollection<ObservableAttribute<dynamic>>
{
}
/// <summary>
/// Wraps a T value and provides INotifyPropertyChanged events. Does not allow setting
/// the value through this interface.
/// </summary>
/// <typeparam name="T">The type of value contained in this field.</typeparam>
public abstract class ObservableAttribute<T> : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
protected T CachedValue;
public T Value
{
get { return CachedValue; }
}
}
/// <summary>
/// Wraps a T value and provides INotifyPropertyChanged events. Does not allow setting
/// the value.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class UpdatableAttribute<T> : ObservableAttribute<T> where T : IComparable
{
public new T Value
{
get { return CachedValue; }
set
{
if (CachedValue.Equals(value)) return;
OnPropertyChanged("Value");
CachedValue = value;
}
}
}
// Signed ints
public class Int8Attribute : UpdatableAttribute<SByte> { }
public class Int16Attribute : UpdatableAttribute<Int16> { }
public class Int32Attribute : UpdatableAttribute<Int32> { }
public class Int64Attribute : UpdatableAttribute<Int64> { }
// Unsigned ints
public class UInt8Attribute : UpdatableAttribute<Byte> { }
public class UInt16Attribute : UpdatableAttribute<UInt16> { }
public class UInt32Attribute : UpdatableAttribute<UInt32> { }
public class UInt64Attribute : UpdatableAttribute<UInt64> { }
// Floating-point
public class Float32Attribute : UpdatableAttribute<Single> { }
public class Float64Attribute : UpdatableAttribute<Double> { }
// String
public class StringAttribute : UpdatableAttribute<String> { }
// Reflexive groups aren't updatable yet, but the properties within a reflexive are
public class ReflexiveAttribute : ObservableAttribute<ObservableObject> { }
}
@ChadSki
Copy link
Author

ChadSki commented May 15, 2014

Prototype for databinding to dynamic objects.

Objects are collections of attributes and notify when attributes have been added or removed.
Attributes contain a single value and notify when that value has changed.

Attributes can hold a primitive type or an IEnumerable list of sub-objects.

Unfortunately, WPF does not play nice with generic types, so concrete subclasses had to be made.

UML Diagram

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment