1 using System; 2 using System.Collections.Generic; 3 using System.Globalization; 4 using System.Linq; 5 using System.Reflection; 6 using System.Text; 7 using System.Text.RegularExpressions; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 using Mesen.GUI.Controls; 11 using Mesen.GUI.Forms.Config; 12 13 namespace Mesen.GUI.Forms 14 { 15 public class EntityBinder 16 { 17 private Dictionary<string, Control> _bindings = new Dictionary<string, Control>(); 18 private Dictionary<string, eNumberFormat> _fieldFormat = new Dictionary<string, eNumberFormat>(); 19 private Dictionary<string, FieldInfoWrapper> _fieldInfo = null; 20 21 public object Entity { get; set; } 22 23 protected virtual Type BindedType 24 { 25 get { return Entity.GetType(); } 26 } 27 28 public bool Updating { get; private set; } 29 AddBinding(string fieldName, Control bindedField, eNumberFormat format = eNumberFormat.Default)30 public void AddBinding(string fieldName, Control bindedField, eNumberFormat format = eNumberFormat.Default) 31 { 32 if(BindedType == null) { 33 throw new Exception("Need to override BindedType to use bindings"); 34 } 35 36 if(_fieldInfo == null) { 37 _fieldInfo = new Dictionary<string, FieldInfoWrapper>(); 38 PropertyInfo[] properties = BindedType.GetProperties(); 39 foreach(PropertyInfo info in properties) { 40 _fieldInfo[info.Name] = new FieldInfoWrapper(info); 41 } 42 43 FieldInfo[] members = BindedType.GetFields(); 44 foreach(FieldInfo info in members) { 45 _fieldInfo[info.Name] = new FieldInfoWrapper(info); 46 } 47 } 48 49 if(_fieldInfo.ContainsKey(fieldName)) { 50 Type fieldType = _fieldInfo[fieldName].FieldType; 51 if(fieldType.IsSubclassOf(typeof(Enum)) && bindedField is ComboBox) { 52 BaseConfigForm.InitializeComboBox(((ComboBox)bindedField), fieldType); 53 } 54 _bindings[fieldName] = bindedField; 55 _fieldFormat[fieldName] = format; 56 } else { 57 throw new Exception("Invalid field name"); 58 } 59 } 60 UpdateUI()61 public void UpdateUI() 62 { 63 this.Updating = true; 64 65 foreach(KeyValuePair<string, Control> kvp in _bindings) { 66 if(!_fieldInfo.ContainsKey(kvp.Key)) { 67 throw new Exception("Invalid binding key"); 68 } else { 69 FieldInfoWrapper field = _fieldInfo[kvp.Key]; 70 eNumberFormat format = _fieldFormat[kvp.Key]; 71 object value = field.GetValue(this.Entity); 72 if(kvp.Value is TextBox) { 73 if(value is IFormattable) { 74 kvp.Value.Text = ((IFormattable)value).ToString(format == eNumberFormat.Decimal ? "" : "X", System.Globalization.CultureInfo.InvariantCulture); 75 } else { 76 kvp.Value.Text = value == null ? "" : ((string)value).Replace(Environment.NewLine, "\n").Replace("\n", Environment.NewLine); 77 } 78 } else if(kvp.Value is ctrlPathSelection) { 79 kvp.Value.Text = (string)value; 80 } else if(kvp.Value is CheckBox) { 81 ((CheckBox)kvp.Value).Checked = Convert.ToBoolean(value); 82 } else if(kvp.Value is ctrlRiskyOption) { 83 ((ctrlRiskyOption)kvp.Value).Checked = Convert.ToBoolean(value); 84 } else if(kvp.Value is RadioButton) { 85 ((RadioButton)kvp.Value).Checked = (bool)value; 86 } else if(kvp.Value is Panel) { 87 RadioButton radio = kvp.Value.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Tag.Equals(value)); 88 if(radio != null) { 89 radio.Checked = true; 90 } else { 91 throw new Exception("No radio button matching value found"); 92 } 93 } else if(kvp.Value is ctrlTrackbar) { 94 if(field.FieldType == typeof(Int32)) { 95 ((ctrlTrackbar)kvp.Value).Value = (int)value; 96 } else { 97 ((ctrlTrackbar)kvp.Value).Value = (int)(uint)value; 98 } 99 } else if(kvp.Value is ctrlHorizontalTrackbar) { 100 ((ctrlHorizontalTrackbar)kvp.Value).Value = (int)value; 101 } else if(kvp.Value is TrackBar) { 102 if(field.FieldType == typeof(Int32)) { 103 ((TrackBar)kvp.Value).Value = (int)value; 104 } else { 105 ((TrackBar)kvp.Value).Value = (int)(uint)value; 106 } 107 } else if(kvp.Value is MesenNumericUpDown) { 108 MesenNumericUpDown nud = kvp.Value as MesenNumericUpDown; 109 decimal val; 110 if(field.FieldType == typeof(UInt32)) { 111 val = (UInt32)value; 112 } else if(field.FieldType == typeof(Int32)) { 113 val = (Int32)value; 114 } else { 115 val = (decimal)(double)value; 116 } 117 val = Math.Min(Math.Max(val, nud.Minimum), nud.Maximum); 118 nud.Value = val; 119 } else if(kvp.Value is ComboBox) { 120 ComboBox combo = kvp.Value as ComboBox; 121 if(value is Enum) { 122 combo.SelectedItem = ResourceHelper.GetEnumText((Enum)value); 123 } else if(field.FieldType == typeof(UInt32)) { 124 for(int i = 0, len = combo.Items.Count; i < len; i++) { 125 UInt32 numericValue; 126 string item = Regex.Replace(combo.Items[i].ToString(), "[^0-9]", ""); 127 if(UInt32.TryParse(item, out numericValue)) { 128 if(numericValue == (UInt32)value) { 129 combo.SelectedIndex = i; 130 break; 131 } 132 } 133 } 134 } else if(field.FieldType == typeof(string)) { 135 combo.SelectedItem = value; 136 if(combo.SelectedIndex < 0 && combo.Items.Count > 0) { 137 combo.SelectedIndex = 0; 138 } 139 } 140 } 141 } 142 } 143 144 this.Updating = false; 145 } 146 UpdateObject()147 public void UpdateObject() 148 { 149 foreach(KeyValuePair<string, Control> kvp in _bindings) { 150 if(!_fieldInfo.ContainsKey(kvp.Key)) { 151 throw new Exception("Invalid binding key"); 152 } else { 153 try { 154 FieldInfoWrapper field = _fieldInfo[kvp.Key]; 155 eNumberFormat format = _fieldFormat[kvp.Key]; 156 if(kvp.Value is TextBox) { 157 object value = kvp.Value.Text; 158 NumberStyles numberStyle = format == eNumberFormat.Decimal ? NumberStyles.Integer : NumberStyles.HexNumber; 159 if(field.FieldType != typeof(string)) { 160 value = ((string)value).Trim().Replace("$", "").Replace("0x", ""); 161 if(string.IsNullOrWhiteSpace((string)value)) { 162 value = "0"; 163 } 164 } 165 if(field.FieldType == typeof(UInt32)) { 166 UInt32 result; 167 if(!UInt32.TryParse((string)value, numberStyle, null, out result)) { 168 continue; //Invalid value, ignore it 169 } 170 value = result; 171 } else if(field.FieldType == typeof(Int32)) { 172 Int32 result; 173 if(!Int32.TryParse((string)value, numberStyle, null, out result)) { 174 continue; //Invalid value, ignore it 175 } 176 value = result; 177 } else if(field.FieldType == typeof(Byte)) { 178 Byte result; 179 if(!Byte.TryParse((string)value, numberStyle, null, out result)) { 180 continue; //Invalid value, ignore it 181 } 182 value = result; 183 } else if(field.FieldType == typeof(UInt16)) { 184 UInt16 result; 185 if(!UInt16.TryParse((string)value, numberStyle, null, out result)) { 186 continue; //Invalid value, ignore it 187 } 188 value = result; 189 } else if(field.FieldType == typeof(UInt64)) { 190 UInt64 result; 191 if(!UInt64.TryParse((string)value, numberStyle, null, out result)) { 192 continue; //Invalid value, ignore it 193 } 194 value = result; 195 } else if(field.FieldType == typeof(Int64)) { 196 Int64 result; 197 if(!Int64.TryParse((string)value, numberStyle, null, out result)) { 198 continue; //Invalid value, ignore it 199 } 200 value = result; 201 } 202 field.SetValue(Entity, value); 203 } else if(kvp.Value is ctrlPathSelection) { 204 field.SetValue(Entity, ((ctrlPathSelection)kvp.Value).Text); 205 } else if(kvp.Value is CheckBox) { 206 if(field.FieldType == typeof(bool)) { 207 field.SetValue(Entity, ((CheckBox)kvp.Value).Checked); 208 } else if(field.FieldType == typeof(byte)) { 209 field.SetValue(Entity, ((CheckBox)kvp.Value).Checked ? (byte)1 : (byte)0); 210 } 211 } else if(kvp.Value is ctrlRiskyOption) { 212 if(field.FieldType == typeof(bool)) { 213 field.SetValue(Entity, ((ctrlRiskyOption)kvp.Value).Checked); 214 } else if(field.FieldType == typeof(byte)) { 215 field.SetValue(Entity, ((ctrlRiskyOption)kvp.Value).Checked ? (byte)1 : (byte)0); 216 } 217 } else if(kvp.Value is RadioButton) { 218 field.SetValue(Entity, ((RadioButton)kvp.Value).Checked); 219 } else if(kvp.Value is Panel) { 220 field.SetValue(Entity, kvp.Value.Controls.OfType<RadioButton>().FirstOrDefault(r => r.Checked).Tag); 221 } else if(kvp.Value is ctrlTrackbar) { 222 if(field.FieldType == typeof(Int32)) { 223 field.SetValue(Entity, (Int32)((ctrlTrackbar)kvp.Value).Value); 224 } else { 225 field.SetValue(Entity, (UInt32)((ctrlTrackbar)kvp.Value).Value); 226 } 227 } else if(kvp.Value is ctrlHorizontalTrackbar) { 228 field.SetValue(Entity, (Int32)((ctrlHorizontalTrackbar)kvp.Value).Value); 229 } else if(kvp.Value is TrackBar) { 230 if(field.FieldType == typeof(Int32)) { 231 field.SetValue(Entity, ((TrackBar)kvp.Value).Value); 232 } else { 233 field.SetValue(Entity, (UInt32)((TrackBar)kvp.Value).Value); 234 } 235 } else if(kvp.Value is MesenNumericUpDown) { 236 if(field.FieldType == typeof(UInt32)) { 237 field.SetValue(Entity, (UInt32)((MesenNumericUpDown)kvp.Value).Value); 238 } else if(field.FieldType == typeof(Int32)) { 239 field.SetValue(Entity, (Int32)((MesenNumericUpDown)kvp.Value).Value); 240 } else { 241 field.SetValue(Entity, (double)((MesenNumericUpDown)kvp.Value).Value); 242 } 243 } else if(kvp.Value is ComboBox) { 244 if(field.FieldType.IsSubclassOf(typeof(Enum))) { 245 Enum enumValue = ((ComboBox)kvp.Value).GetEnumValue(field.FieldType); 246 if(enumValue != null) { 247 field.SetValue(Entity, enumValue); 248 } 249 } else if(field.FieldType == typeof(UInt32)) { 250 UInt32 numericValue; 251 string item = Regex.Replace(((ComboBox)kvp.Value).SelectedItem.ToString(), "[^0-9]", ""); 252 if(UInt32.TryParse(item, out numericValue)) { 253 field.SetValue(Entity, numericValue); 254 } 255 } else if(field.FieldType == typeof(string)) { 256 field.SetValue(Entity, ((ComboBox)kvp.Value).SelectedItem); 257 } 258 } 259 } catch { 260 //Ignore exceptions caused by bad user input 261 } 262 } 263 } 264 } 265 private class FieldInfoWrapper 266 { 267 private FieldInfo _fieldInfo; 268 private PropertyInfo _propertyInfo; 269 FieldInfoWrapper(PropertyInfo info)270 public FieldInfoWrapper(PropertyInfo info) 271 { 272 _propertyInfo = info; 273 } 274 FieldInfoWrapper(FieldInfo info)275 public FieldInfoWrapper(FieldInfo info) 276 { 277 _fieldInfo = info; 278 } 279 280 public Type FieldType 281 { 282 get 283 { 284 if(_fieldInfo != null) { 285 return _fieldInfo.FieldType; 286 } else { 287 return _propertyInfo.PropertyType; 288 } 289 } 290 } 291 SetValue(object obj, object value)292 public void SetValue(object obj, object value) 293 { 294 if(_fieldInfo != null) { 295 _fieldInfo.SetValue(obj, value); 296 } else { 297 _propertyInfo.SetValue(obj, value); 298 } 299 } 300 GetValue(object obj)301 public object GetValue(object obj) 302 { 303 if(_fieldInfo != null) { 304 return _fieldInfo.GetValue(obj); 305 } else { 306 return _propertyInfo.GetValue(obj); 307 } 308 } 309 } 310 } 311 312 public enum eNumberFormat 313 { 314 Default, 315 Hex, 316 Decimal, 317 } 318 } 319