зеркало из https://github.com/jsuarezruiz/HotUI.git
Merge branch 'master' of https://github.com/Clancey/HotForms into mac
This commit is contained in:
Коммит
f98c912170
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -35,18 +35,18 @@ namespace HotUI.Forms.Sample {
|
|||
protected override View Build () =>
|
||||
new ScrollView{new Stack {
|
||||
(state.CanEdit ?
|
||||
(View)new Entry {
|
||||
Text = state.Text,
|
||||
(View)new Entry(state.Text){
|
||||
Completed =(e)=> state.Text = e
|
||||
}
|
||||
: new Label { TextBinding = () => $"{state.Text}: multiText" }),// Fromated Text will warn you. This should be done by TextBinding
|
||||
new Label {Text = state.Text},
|
||||
new Button{Text = "Toggle Entry/Label", OnClick = ()=> state.CanEdit = !state.CanEdit},
|
||||
new Button{Text = "Update Text", OnClick = ()=>{
|
||||
: new Label (() => $"{state.Text}: multiText" )),// Fromated Text will warn you. This should be done by TextBinding
|
||||
new Label (state.Text),
|
||||
new Button("Toggle Entry/Label"){ OnClick = ()=> state.CanEdit = !state.CanEdit},
|
||||
new Button("Update Text"){ OnClick = ()=>{
|
||||
state.Text = $"Click Count: {clickCount.Value++}";
|
||||
}
|
||||
}
|
||||
} };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,21 +29,18 @@ namespace HotUI.Samples {
|
|||
}
|
||||
|
||||
protected override View Build () =>
|
||||
//new ScrollView{
|
||||
new ScrollView{
|
||||
new Stack {
|
||||
(state.CanEdit ?
|
||||
(View)new Entry {
|
||||
Text = state.Text,
|
||||
Completed =(e)=> state.Text = e
|
||||
}
|
||||
: new Label { TextBinding = () => $"{state.Text}: multiText" }),// Fromated Text will warn you. This should be done by TextBinding
|
||||
new Label {Text = state.Text},
|
||||
new Button{Text = "Toggle Entry/Label", OnClick = ()=> state.CanEdit = !state.CanEdit},
|
||||
new Button{Text = "Update Text", OnClick = ()=>{
|
||||
(state.CanEdit ? (View)new Entry(state.Text) {
|
||||
Completed =(e)=> state.Text = e
|
||||
} : new Label (() => $"{state.Text}: multiText" )),// Fromated Text will warn you. This should be done by TextBinding
|
||||
new Label (state.Text),
|
||||
new Button("Toggle Entry/Label"){ OnClick = ()=> state.CanEdit = !state.CanEdit},
|
||||
new Button("Update Text"){ OnClick = ()=>{
|
||||
state.Text = $"Click Count: {clickCount.Value++}";
|
||||
}
|
||||
}
|
||||
//}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +1,212 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace HotUI {
|
||||
|
||||
|
||||
public interface INotifyPropertyRead : INotifyPropertyChanged {
|
||||
event PropertyChangedEventHandler PropertyRead;
|
||||
}
|
||||
public class BindingObject : INotifyPropertyRead {
|
||||
|
||||
public class BindingObject : INotifyPropertyChanged {
|
||||
|
||||
public event PropertyChangedEventHandler PropertyRead;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
internal Action StateChanged;
|
||||
internal protected Dictionary<string, object> dictionary = new Dictionary<string, object> ();
|
||||
|
||||
internal protected Action<BindingObject, List<(string property, object value)>> UpdateParentValueChanged;
|
||||
internal protected string ParentProperty { get; set; }
|
||||
|
||||
BindingState bindingState = new BindingState ();
|
||||
public BindingState BindingState {
|
||||
get => bindingState;
|
||||
set {
|
||||
if (bindingState == value)
|
||||
return;
|
||||
bindingState = value;
|
||||
foreach (var child in bindableChildren) {
|
||||
child.BindingState = value;
|
||||
}
|
||||
}
|
||||
protected T GetProperty<T> ([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
PropertyRead?.Invoke (this, new PropertyChangedEventArgs (propertyName));
|
||||
if (dictionary.TryGetValue (propertyName, out var val))
|
||||
return (T)val;
|
||||
return default;
|
||||
}
|
||||
|
||||
internal object GetValue (string propertyName)
|
||||
{
|
||||
dictionary.TryGetValue (propertyName, out var val);
|
||||
return val;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true if the value changed
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="currentValue"></param>
|
||||
/// <param name="newValue"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <returns></returns>
|
||||
protected bool SetProperty<T> (T value, [CallerMemberName] string propertyName = "")
|
||||
{
|
||||
if (dictionary.TryGetValue (propertyName, out object val)) {
|
||||
if (EqualityComparer<T>.Default.Equals ((T)val, value))
|
||||
return false;
|
||||
}
|
||||
dictionary [propertyName] = value;
|
||||
OnPropertyChanged?.Invoke ((this, propertyName, value));
|
||||
PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
|
||||
return true;
|
||||
}
|
||||
|
||||
internal Action<(object Sender, string PropertyName, object Value)> OnPropertyChanged { get; set; }
|
||||
}
|
||||
|
||||
public class BindingObjectManager {
|
||||
|
||||
public BindingState BindingState { get; set; } = new BindingState ();
|
||||
internal Action StateChanged;
|
||||
|
||||
bool isBuilding;
|
||||
public bool IsBuilding => isBuilding;
|
||||
|
||||
|
||||
public IEnumerable<KeyValuePair<string, object>> ChangedProperties => changeDictionary;
|
||||
Dictionary<string, object> changeDictionary = new Dictionary<string, object> ();
|
||||
List<(string property, object value)> pendingUpdates = new List<(string, object)> ();
|
||||
|
||||
|
||||
List<string> listProperties = new List<string> ();
|
||||
|
||||
internal void ResetChangeDictionary ()
|
||||
{
|
||||
changeDictionary.Clear ();
|
||||
}
|
||||
|
||||
|
||||
Dictionary<string, object> changeDictionary = new Dictionary<string, object> ();
|
||||
internal protected Dictionary<string, object> dictionary = new Dictionary<string, object> ();
|
||||
List<(string property, object value)> pendingUpdates = new List<(string, object)> ();
|
||||
|
||||
|
||||
|
||||
bool isBuilding;
|
||||
public bool IsBuilding => isBuilding;
|
||||
|
||||
internal void StartBuildingView ()
|
||||
{
|
||||
CheckForStateAttributes ();
|
||||
CheckForStateAttributes (this);
|
||||
isBuilding = true;
|
||||
bindableChildren.ForEach (x => x.StartBuildingView ());
|
||||
if (listProperties.Any ()) {
|
||||
BindingState.AddGlobalProperties (listProperties);
|
||||
}
|
||||
listProperties.Clear ();
|
||||
}
|
||||
|
||||
bool hasChecked = false;
|
||||
static Assembly HotUIAssembly = typeof (BindingObject).Assembly;
|
||||
void CheckForStateAttributes ()
|
||||
List<INotifyPropertyRead> children = new List<INotifyPropertyRead> ();
|
||||
Dictionary<object, string> childrenProperty = new Dictionary<object, string> ();
|
||||
|
||||
public void StartMonitoring (INotifyPropertyRead obj)
|
||||
{
|
||||
if (hasChecked)
|
||||
if (children.Contains (obj))
|
||||
return;
|
||||
var type = this.GetType ();
|
||||
children.Add (obj);
|
||||
//Check in for more properties!
|
||||
CheckForStateAttributes (obj);
|
||||
|
||||
if (obj is BindingObject bobj) {
|
||||
bobj.OnPropertyChanged = (s) => OnPropertyChanged (s.Sender, s.PropertyName, s.Value);
|
||||
} else {
|
||||
obj.PropertyChanged += Obj_PropertyChanged;
|
||||
}
|
||||
obj.PropertyRead += Obj_PropertyRead;
|
||||
}
|
||||
|
||||
private void Obj_PropertyRead (object sender, PropertyChangedEventArgs e) => OnPropertyRead (sender, e.PropertyName);
|
||||
|
||||
private void Obj_PropertyChanged (object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is BindingObject b) {
|
||||
OnPropertyChanged (sender, e.PropertyName, b.GetValue (e.PropertyName));
|
||||
return;
|
||||
}
|
||||
|
||||
var value = sender.GetPropertyValue (e.PropertyName);
|
||||
OnPropertyChanged (sender, e.PropertyName, value);
|
||||
}
|
||||
|
||||
public void StopMonitoring (INotifyPropertyRead obj)
|
||||
{
|
||||
if (!children.Contains (obj))
|
||||
return;
|
||||
children.Remove (obj);
|
||||
if (obj is BindingObject b) {
|
||||
b.OnPropertyChanged = null;
|
||||
} else {
|
||||
obj.PropertyChanged -= Obj_PropertyRead;
|
||||
}
|
||||
obj.PropertyRead -= Obj_PropertyRead;
|
||||
|
||||
}
|
||||
|
||||
internal void EndBuildingView ()
|
||||
{
|
||||
listProperties.Clear ();
|
||||
isBuilding = false;
|
||||
}
|
||||
|
||||
internal void StartProperty ()
|
||||
{
|
||||
isBuilding = true;
|
||||
if (listProperties.Any ()) {
|
||||
BindingState.AddGlobalProperties (listProperties);
|
||||
}
|
||||
listProperties.Clear ();
|
||||
}
|
||||
|
||||
internal string [] EndProperty (bool includeParent = false)
|
||||
{
|
||||
var changed = listProperties.Distinct ().ToArray ();
|
||||
listProperties.Clear ();
|
||||
return changed;
|
||||
|
||||
}
|
||||
|
||||
bool isUpdating;
|
||||
public void StartUpdate ()
|
||||
{
|
||||
isUpdating = true;
|
||||
}
|
||||
|
||||
public void EndUpdate ()
|
||||
{
|
||||
isUpdating = false;
|
||||
if (pendingUpdates.Any ()) {
|
||||
if (!BindingState.UpdateValues (pendingUpdates)) {
|
||||
pendingUpdates.Clear ();
|
||||
StateChanged?.Invoke ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
pendingUpdates.Clear ();
|
||||
}
|
||||
|
||||
|
||||
void OnPropertyChanged (object sender, string propertyName, object value)
|
||||
{
|
||||
if (value?.GetType () == typeof (View))
|
||||
return;
|
||||
|
||||
changeDictionary [propertyName] = value;
|
||||
childrenProperty.TryGetValue (sender, out var parentproperty);
|
||||
var prop = string.IsNullOrWhiteSpace (parentproperty) ? propertyName : $"{parentproperty}.{propertyName}";
|
||||
pendingUpdates.Add ((prop, value));
|
||||
if (!isUpdating) {
|
||||
EndUpdate ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OnPropertyRead (object sender, string propertyName)
|
||||
{
|
||||
if (!isBuilding)
|
||||
return;
|
||||
childrenProperty.TryGetValue (sender, out var parentproperty);
|
||||
var prop = string.IsNullOrWhiteSpace (parentproperty) ? propertyName : $"{parentproperty}.{propertyName}";
|
||||
listProperties.Add (prop);
|
||||
}
|
||||
|
||||
|
||||
bool hasChecked;
|
||||
static Assembly HotUIAssembly = typeof (BindingObject).Assembly;
|
||||
void CheckForStateAttributes (object obj)
|
||||
{
|
||||
if (hasChecked && obj == this)
|
||||
return;
|
||||
var type = obj.GetType ();
|
||||
//var properties = type.GetProperties (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).
|
||||
// Where (x => Attribute.IsDefined (x, typeof (StateAttribute))).ToList ();
|
||||
var fields = type.GetFields (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).
|
||||
|
@ -84,9 +223,10 @@ namespace HotUI {
|
|||
|
||||
if (fields.Any ()) {
|
||||
foreach (var field in fields) {
|
||||
var child = field.GetValue (this) as BindingObject;
|
||||
var child = field.GetValue (obj) as INotifyPropertyRead;
|
||||
if (child != null) {
|
||||
SetProperty (child, field.Name);
|
||||
childrenProperty [child] = field.Name;
|
||||
StartMonitoring (child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,148 +234,63 @@ namespace HotUI {
|
|||
hasChecked = true;
|
||||
}
|
||||
|
||||
internal void EndBuildingView ()
|
||||
{
|
||||
}
|
||||
|
||||
bindableChildren.ForEach (x => x.EndBuildingView ());
|
||||
listProperties.Clear ();
|
||||
isBuilding = false;
|
||||
public class BindingState {
|
||||
public List<string> GlobalProperties { get; set; } = new List<string> ();
|
||||
public Dictionary<string, List<Action<string, object>>> ViewUpdateProperties = new Dictionary<string, List<Action<string, object>>> ();
|
||||
public void AddGlobalProperty (string property)
|
||||
{
|
||||
if (GlobalProperties.Contains (property))
|
||||
return;
|
||||
Debug.WriteLine ($"Adding Global Property: {property}");
|
||||
GlobalProperties.Add (property);
|
||||
}
|
||||
public void AddGlobalProperties (IEnumerable<string> properties)
|
||||
{
|
||||
foreach (var prop in properties)
|
||||
AddGlobalProperty (prop);
|
||||
}
|
||||
public void AddViewProperty (string property, Action<string, object> update)
|
||||
{
|
||||
if (!ViewUpdateProperties.TryGetValue (property, out var actions))
|
||||
ViewUpdateProperties [property] = actions = new List<Action<string, object>> ();
|
||||
actions.Add (update);
|
||||
}
|
||||
|
||||
List<string> listProperties = new List<string> ();
|
||||
internal void StartProperty ()
|
||||
public void AddViewProperty (string [] properties, Action<string, object> update)
|
||||
{
|
||||
isBuilding = true;
|
||||
if (listProperties.Any ()) {
|
||||
BindingState.AddGlobalProperties (listProperties);
|
||||
foreach (var property in properties) {
|
||||
AddViewProperty (property, update);
|
||||
}
|
||||
listProperties.Clear ();
|
||||
|
||||
bindableChildren.ForEach (x => x.StartProperty ());
|
||||
}
|
||||
|
||||
internal string [] EndProperty (bool includeParent = false)
|
||||
public void Clear ()
|
||||
{
|
||||
var children = bindableChildren.SelectMany (x => x.EndProperty (true));
|
||||
var props = listProperties.Select (x => includeParent ? $"{ParentProperty}.{x}" : x).Union (children).Distinct ().ToArray ();
|
||||
listProperties.Clear ();
|
||||
return props;
|
||||
|
||||
}
|
||||
|
||||
//private List<string> CheckChildrenProperties(List<string> properties)
|
||||
//{
|
||||
// List<string> realProperties = new List<string> ();
|
||||
// foreach(var prop in properties) {
|
||||
// if(bindableChildren.TryGetValue(prop, out var child)) {
|
||||
// var childProps =
|
||||
// }
|
||||
// realProperties.Add (prop);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
bool isUpdating;
|
||||
public void StartUpdate ()
|
||||
{
|
||||
isUpdating = true;
|
||||
}
|
||||
|
||||
public void EndUpdate ()
|
||||
{
|
||||
isUpdating = false;
|
||||
|
||||
|
||||
if (pendingUpdates.Any ()) {
|
||||
if (UpdateParentValueChanged != null) {
|
||||
var updates = pendingUpdates.ToList ();
|
||||
pendingUpdates.Clear ();
|
||||
UpdateParentValueChanged (this, updates);
|
||||
} else if (!BindingState.UpdateValues (pendingUpdates)) {
|
||||
pendingUpdates.Clear ();
|
||||
StateChanged?.Invoke ();
|
||||
return;
|
||||
}
|
||||
GlobalProperties?.Clear ();
|
||||
foreach (var key in ViewUpdateProperties) {
|
||||
key.Value.Clear ();
|
||||
}
|
||||
pendingUpdates.Clear ();
|
||||
ViewUpdateProperties.Clear ();
|
||||
}
|
||||
|
||||
|
||||
protected T GetProperty<T> ([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
//Ignore View for the ViewBuilders
|
||||
if (isBuilding && typeof(T) != typeof(View)) {
|
||||
listProperties.Add (propertyName);
|
||||
}
|
||||
|
||||
if (dictionary.TryGetValue (propertyName, out var val))
|
||||
return (T)val;
|
||||
return default (T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the value changed
|
||||
/// This returns true, if it updated the UI based on the changes
|
||||
/// False, if it couldnt update, or the value was global so the whole UI needs refreshed
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="currentValue"></param>
|
||||
/// <param name="newValue"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="updates"></param>
|
||||
/// <returns></returns>
|
||||
protected bool SetProperty<T> (T value, [CallerMemberName] string propertyName = "")
|
||||
public bool UpdateValues (IEnumerable<(string property, object value)> updates)
|
||||
{
|
||||
|
||||
if (dictionary.TryGetValue (propertyName, out object val)) {
|
||||
if (EqualityComparer<T>.Default.Equals ((T)val, value))
|
||||
return true;
|
||||
if (val is BindingObject oldChild) {
|
||||
UntrackChild (propertyName, oldChild);
|
||||
bool didUpdate = true;
|
||||
foreach (var update in updates) {
|
||||
if (GlobalProperties.Contains (update.property))
|
||||
return false;
|
||||
if (ViewUpdateProperties.TryGetValue (update.property, out var actions)) {
|
||||
foreach (var a in actions)
|
||||
a.Invoke (update.property, update.value);
|
||||
didUpdate = true;
|
||||
}
|
||||
}
|
||||
if (value is BindingObject b) {
|
||||
TrackChild (propertyName, b);
|
||||
}
|
||||
dictionary [propertyName] = value;
|
||||
//If we track the ViewBuilder.View property it can easily get into a loop!
|
||||
if (typeof (T) != typeof (View)) {
|
||||
changeDictionary [propertyName] = value;
|
||||
//If this is tied to a parent, we need to send that notification as well
|
||||
if (!string.IsNullOrWhiteSpace (ParentProperty))
|
||||
pendingUpdates.Add (($"{ParentProperty}.{propertyName}", value));
|
||||
pendingUpdates.Add ((propertyName, value));
|
||||
if (!isUpdating) {
|
||||
EndUpdate ();
|
||||
}
|
||||
}
|
||||
PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
|
||||
return true;
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
List<BindingObject> bindableChildren = new List<BindingObject> ();
|
||||
|
||||
void TrackChild (string propertyName, BindingObject child)
|
||||
{
|
||||
//This should fail if there are two properties with the same binding object as it's value. But that should never happen!
|
||||
child.ParentProperty = propertyName;
|
||||
child.UpdateParentValueChanged = Child_PropertiesChanged;
|
||||
child.BindingState = this.BindingState;
|
||||
bindableChildren.Add (child);
|
||||
}
|
||||
|
||||
private void Child_PropertiesChanged (BindingObject child, List<(string property, object value)> changes)
|
||||
{
|
||||
pendingUpdates.AddRange (changes);
|
||||
EndUpdate ();
|
||||
}
|
||||
|
||||
void UntrackChild (string propertyName, BindingObject child)
|
||||
{
|
||||
child.UpdateParentValueChanged = null;
|
||||
child.ParentProperty = null;
|
||||
child.BindingState = new BindingState ();
|
||||
bindableChildren.Remove (child);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
using System;
|
||||
namespace HotUI {
|
||||
public class Button : View {
|
||||
public Button ()
|
||||
{
|
||||
|
||||
}
|
||||
public Button (string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
public Button (Func<string> formatedText)
|
||||
{
|
||||
TextBinding = formatedText;
|
||||
}
|
||||
private string text;
|
||||
public string Text {
|
||||
get => text;
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
using System;
|
||||
namespace HotUI {
|
||||
public class Entry : View {
|
||||
public Entry ()
|
||||
{
|
||||
|
||||
}
|
||||
public Entry (string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
public Entry (Func<string> formatedText)
|
||||
{
|
||||
TextBinding = formatedText;
|
||||
}
|
||||
|
||||
string text;
|
||||
public string Text {
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
using System;
|
||||
namespace HotUI {
|
||||
public class Image : View {
|
||||
public Image () { }
|
||||
public Image(string source)
|
||||
{
|
||||
Source = source;
|
||||
}
|
||||
string source;
|
||||
public string Source {
|
||||
get => source;
|
||||
|
|
|
@ -2,7 +2,18 @@
|
|||
using System.Diagnostics;
|
||||
namespace HotUI {
|
||||
public class Label : View {
|
||||
public Label()
|
||||
{
|
||||
|
||||
}
|
||||
public Label(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
public Label(Func<string> formatedText)
|
||||
{
|
||||
TextBinding = formatedText;
|
||||
}
|
||||
private string text;
|
||||
public string Text {
|
||||
get => text;
|
||||
|
|
|
@ -13,17 +13,19 @@ namespace HotUI {
|
|||
{
|
||||
ReBuildView ();
|
||||
}
|
||||
|
||||
View view;
|
||||
public View View {
|
||||
get => GetProperty<View> ();
|
||||
get => view;
|
||||
protected set {
|
||||
if (SetProperty (value)) {
|
||||
ViewHandler?.SetView (value);
|
||||
}
|
||||
if (view == value)
|
||||
return;
|
||||
view = value;
|
||||
ViewHandler?.SetView (value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void ReBuildView()
|
||||
public void ReBuildView ()
|
||||
{
|
||||
var oldView = View;
|
||||
BindingState.Clear ();
|
||||
|
@ -59,83 +61,4 @@ namespace HotUI {
|
|||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public abstract class StateViewBuilder {
|
||||
|
||||
State state;
|
||||
public State State {
|
||||
get {
|
||||
if (state == null) {
|
||||
state = new State ();
|
||||
CreateState (state);
|
||||
//state.StateChanged = Reload;
|
||||
state.ResetChangeDictionary ();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
set => state = value;
|
||||
}
|
||||
|
||||
protected abstract void CreateState (dynamic state);
|
||||
|
||||
protected abstract View Build (dynamic state);
|
||||
}
|
||||
|
||||
public class BindingState {
|
||||
public List<string> GlobalProperties { get; set; } = new List<string> ();
|
||||
public Dictionary<string, List<Action<string,object>>> ViewUpdateProperties = new Dictionary<string, List<Action<string,object>>> ();
|
||||
public void AddGlobalProperty (string property)
|
||||
{
|
||||
Debug.WriteLine ($"Adding Global Property: {property}");
|
||||
GlobalProperties.Add (property);
|
||||
}
|
||||
public void AddGlobalProperties(IEnumerable<string> properties)
|
||||
{
|
||||
foreach(var prop in properties)
|
||||
AddGlobalProperty (prop);
|
||||
}
|
||||
public void AddViewProperty(string property, Action<string,object> update)
|
||||
{
|
||||
if (!ViewUpdateProperties.TryGetValue (property, out var actions))
|
||||
ViewUpdateProperties[property] = actions = new List<Action<string,object>> ();
|
||||
actions.Add (update);
|
||||
}
|
||||
|
||||
public void AddViewProperty (string[] properties, Action<string,object> update)
|
||||
{
|
||||
foreach(var property in properties) {
|
||||
AddViewProperty (property, update);
|
||||
}
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
GlobalProperties?.Clear ();
|
||||
foreach(var key in ViewUpdateProperties) {
|
||||
key.Value.Clear ();
|
||||
}
|
||||
ViewUpdateProperties.Clear ();
|
||||
}
|
||||
/// <summary>
|
||||
/// This returns true, if it updated the UI based on the changes
|
||||
/// False, if it couldnt update, or the value was global so the whole UI needs refreshed
|
||||
/// </summary>
|
||||
/// <param name="updates"></param>
|
||||
/// <returns></returns>
|
||||
public bool UpdateValues(IEnumerable<(string property,object value)> updates)
|
||||
{
|
||||
bool didUpdate = true;
|
||||
foreach(var update in updates) {
|
||||
if (GlobalProperties.Contains (update.property))
|
||||
return false;
|
||||
if(ViewUpdateProperties.TryGetValue(update.property, out var actions)) {
|
||||
foreach (var a in actions)
|
||||
a.Invoke (update.property, update.value);
|
||||
didUpdate = true;
|
||||
}
|
||||
}
|
||||
return didUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace HotUI {
|
||||
|
@ -17,7 +18,8 @@ namespace HotUI {
|
|||
if (propCount == 1) {
|
||||
var prop = props [0];
|
||||
|
||||
var stateValue = state.GetValue (prop).Cast<T>();
|
||||
var stateValue = state.GetValue (prop).Cast<T> ();
|
||||
var old = state.EndProperty ();
|
||||
//1 to 1 binding!
|
||||
if (EqualityComparer<T>.Default.Equals (stateValue, newValue)) {
|
||||
state.BindingState.AddViewProperty (prop, onUpdate);
|
||||
|
@ -42,17 +44,16 @@ namespace HotUI {
|
|||
|
||||
onUpdate (propertyName, newValue);
|
||||
}
|
||||
static T Cast<T>(this object val)
|
||||
static T Cast<T> (this object val)
|
||||
{
|
||||
if (val == null)
|
||||
return default;
|
||||
try {
|
||||
if(typeof(T) == typeof(string)) {
|
||||
if (typeof (T) == typeof (string)) {
|
||||
return (T)(object)val?.ToString ();
|
||||
}
|
||||
return (T)val;
|
||||
}
|
||||
catch(Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
//This is ok, sometimes the values are not the same.
|
||||
return default;
|
||||
}
|
||||
|
@ -65,10 +66,10 @@ namespace HotUI {
|
|||
public static View Diff (this View newView, View oldView)
|
||||
{
|
||||
var v = newView.DiffUpdate (oldView);
|
||||
void callUpdateOnView(View view)
|
||||
void callUpdateOnView (View view)
|
||||
{
|
||||
if(view is IContainerView container) {
|
||||
foreach(var child in container.GetChildren()) {
|
||||
if (view is IContainerView container) {
|
||||
foreach (var child in container.GetChildren ()) {
|
||||
callUpdateOnView (child);
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +135,7 @@ namespace HotUI {
|
|||
}
|
||||
}
|
||||
|
||||
newView.UpdateFromOldView(oldView.ViewHandler);
|
||||
newView.UpdateFromOldView (oldView.ViewHandler);
|
||||
|
||||
|
||||
return newView;
|
||||
|
@ -157,5 +158,35 @@ namespace HotUI {
|
|||
return view?.GetType () == compareView?.GetType ();
|
||||
}
|
||||
|
||||
public static object GetPropertyValue (this object obj, string name)
|
||||
{
|
||||
foreach (var part in name.Split ('.')) {
|
||||
if (obj == null)
|
||||
return null;
|
||||
if (obj is BindingObject bo) {
|
||||
obj = bo.GetValue (part);
|
||||
} else {
|
||||
var type = obj.GetType ();
|
||||
var info = type.GetProperty (part, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (info == null) {
|
||||
var field = type.GetField (part, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (field == null)
|
||||
return null;
|
||||
obj = field.GetValue (obj);
|
||||
} else {
|
||||
obj = info.GetValue (obj, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static T GetPropValue<T> (this object obj, string name)
|
||||
{
|
||||
var retval = GetPropertyValue (obj, name);
|
||||
if (retval == null)
|
||||
return default;
|
||||
return (T)retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,19 +46,20 @@ namespace HotUI {
|
|||
|
||||
|
||||
[Serializable]
|
||||
public class State : BindingObject {
|
||||
public class State : BindingObjectManager {
|
||||
internal object GetValue (string property)
|
||||
{
|
||||
var bindingParts = property.Split ('.');
|
||||
var dict = dictionary;
|
||||
for (var i = 0; i < bindingParts.Length - 1; i++) {
|
||||
var part = bindingParts [i];
|
||||
dict.TryGetValue (part, out var val);
|
||||
var child = val as BindingObject;
|
||||
dict = child.dictionary;
|
||||
}
|
||||
dict.TryGetValue (bindingParts.Last (), out var value);
|
||||
return value;
|
||||
return this.GetPropertyValue (property);
|
||||
//var bindingParts = property.Split ('.');
|
||||
//var dict = dictionary;
|
||||
//for (var i = 0; i < bindingParts.Length - 1; i++) {
|
||||
// var part = bindingParts [i];
|
||||
// dict.TryGetValue (part, out var val);
|
||||
// var child = val as BindingObject;
|
||||
// dict = child.dictionary;
|
||||
//}
|
||||
//dict.TryGetValue (bindingParts.Last (), out var value);
|
||||
//return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче