NOT AN ANSWER
Asked for more details and comments have a size limit.
public class MessageModel : INotifyPropertyChanged, INotifyDataErrorInfo
{
public MessageModel()
{
PropertyChanged += MessageModel_PropertyChanged;
DefinedMessages.CollectionChanged += DefinedMessages_CollectionChanged;
}
private string newMessageID;
public string NewMessageID
{
get { return newMessageID; }
set
{
if (newMessageID != value)
{
newMessageID = value;
if (int.TryParse(newMessageID, out int tryVal))
{
if (tryVal >= 10000 && tryVal <= 19999)
{
ClearErrors();
}
else
{
AddError("Message ID must be in the range 10000 to 19999");
}
}
else
{
AddError("Message ID must be numeric");
}
NotifyPropertyChanged();
}
}
}
private DefinedMessage currentMessage = new DefinedMessage();
public DefinedMessage CurrentMessage
{
get { return currentMessage; }
set
{
if (currentMessage != value)
{
Trace.WriteLine($"Setting CurrentMessage {(value == null ? "Null" : "Not Null")}");
currentMessage = value;
if (currentMessage != null && !string.IsNullOrWhiteSpace(currentMessage.MessageName))
{
MessageName = currentMessage.MessageName;
}
NotifyPropertyChanged();
}
}
}
private ToolTip messageIDTip;
public ToolTip MessageIDTip
{
get { return messageIDTip; }
set
{
if(messageIDTip!=value)
{
messageIDTip = value;
NotifyPropertyChanged();
}
}
}
//For serialization purposes
private string messageName;
public string MessageName
{
get { return messageName; }
set
{
if (messageName != value)
{
messageName = value;
if (currentMessage != null)
{
currentMessage.MessageName = MessageName;
}
NotifyPropertyChanged();
}
}
}
private ObservableCollection<DefinedMessage> definedMessages = new ObservableCollection<DefinedMessage>();
public ObservableCollection<DefinedMessage> DefinedMessages { get { return definedMessages; } }
private List<FieldSizeType> fieldSizes = new List<FieldSizeType>()
{new FieldSizeType("Byte", 1), new FieldSizeType("Short", 2), new FieldSizeType("Int", 4),
new FieldSizeType("Date", 4), new FieldSizeType("Binary", -1), new FieldSizeType("Ascii", -1),
new FieldSizeType("StringNullEnd", -1), new FieldSizeType("Remainder", -2), };
public List<FieldSizeType> FieldSizes { get { return fieldSizes; } }
private DefinedFieldRuleTypes rules = new DefinedFieldRuleTypes()
{ new FieldRuleTypes("Required", 0), //Standard
new FieldRuleTypes("Array Length", 1), //Array length (next item)
new FieldRuleTypes("Dependent", 2), //Only present if previous length > 0
new FieldRuleTypes("Repeat Count", 3), //Count of how iterations of child rows, must be followed by child row definition
new FieldRuleTypes("Enumeration", 4) }; //Enumeration
public DefinedFieldRuleTypes Rules { get { return rules; } }
private void AddError(string error, [CallerMemberName] string propertyName = "" )
{
if (!errorsByPropertyName.ContainsKey(propertyName))
errorsByPropertyName[propertyName] = new List<string>();
if (!errorsByPropertyName[propertyName].Contains(error))
{
errorsByPropertyName[propertyName].Add(error);
string tipMsg = string.Empty;
errorsByPropertyName[propertyName].ForEach(_ => tipMsg += tipMsg == string.Empty ? _ : "\r\n" + _);
switch (propertyName)
{
case "MessageIDTip":
MessageIDTip = new ToolTip();
MessageIDTip.Content = tipMsg;
break;
}
NotifyErrorsChanged(propertyName);
}
}
private void ClearErrors([CallerMemberName] string propertyName = "")
{
if (errorsByPropertyName.ContainsKey(propertyName))
{
errorsByPropertyName.Remove(propertyName);
switch(propertyName)
{
case "MessageIDTip":
MessageIDTip = null;
break;
}
NotifyErrorsChanged(propertyName);
}
}
public void SaveISMPDefinitions()
{
string exeFullPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
string ISMPDefinitionsLocation = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(exeFullPath), "ISMPDefinedMessages.xml");
try
{
XmlSerializer serial = new XmlSerializer(typeof(ObservableCollection<DefinedMessage>));
using (StreamWriter writer = new StreamWriter(ISMPDefinitionsLocation))
{
serial.Serialize(writer, DefinedMessages);
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"Unable to load file ISMPDefinedMessages.xml\r\nError Message:\r\n{ex.Message}", "Error Loading XML ISMP Message Definitions", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
}
}
private Dictionary<string, List<string>> errorsByPropertyName { get; } = new Dictionary<string, List<string>>();
public bool HasErrors { get { return errorsByPropertyName.Any(); } }
public bool PropertyErrors(string propertyName = "")
{
if(string.IsNullOrWhiteSpace(propertyName))
return errorsByPropertyName.Any();
return errorsByPropertyName.ContainsKey(propertyName);
}
public IEnumerable GetErrors(string propertyName)
{
return errorsByPropertyName.ContainsKey(propertyName) ? errorsByPropertyName[propertyName] : null;
}
private void MessageModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch(e.PropertyName)
{
case "NewMessageID":
if (!string.IsNullOrWhiteSpace(NewMessageID) && CurrentMessage == null && !PropertyErrors("NewMessageID"))
{
CurrentMessage = new DefinedMessage();
}
break;
}
}
private void DefinedMessages_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Remove:
break;
}
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
protected void NotifyErrorsChanged(string propertyName)
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
[Serializable]
public class MessageDetailRow : INotifyPropertyChanged
{
public MessageDetailRow()
{
DependentRows.CollectionChanged += DependentRows_CollectionChanged;
}
private decimal id;
public decimal ID
{
get { return id; }
set
{
if (id != value)
{
id = value;
NotifyPropertyChanged();
}
}
}
private string field;
public string Field
{
get { return field; }
set
{
if (field != value)
{
field = value;
NotifyPropertyChanged();
}
}
}
private FieldSizeType selectedFieldSize;
public FieldSizeType SelectedFieldSize
{
get { return selectedFieldSize; }
set
{
if (selectedFieldSize != value)
{
selectedFieldSize = value;
NotifyPropertyChanged();
}
}
}
private FieldRuleTypes selectedRule;
public FieldRuleTypes SelectedRule
{
get { return selectedRule; }
set
{
if (selectedRule != value)
{
selectedRule = value;
NotifyPropertyChanged();
}
}
}
private string description;
public string Description
{
get { return description; }
set
{
if (description != value)
{
description = value;
NotifyPropertyChanged();
}
}
}
private ObservableCollection<MessageDetailRow> dependentRows = new ObservableCollection<MessageDetailRow>();
public ObservableCollection<MessageDetailRow> DependentRows { get { return dependentRows; } }
private void DependentRows_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch(e.Action)
{
case NotifyCollectionChangedAction.Add:
break;
case NotifyCollectionChangedAction.Remove:
break;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ChildRowVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ObservableCollection<MessageDetailRow> rows = value as ObservableCollection<MessageDetailRow>;
if (rows == null)
return System.Windows.Visibility.Collapsed;
else if (rows.Any())
return System.Windows.Visibility.Visible;
else
return System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class FieldRuleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
FieldRuleTypes rule = value as FieldRuleTypes;
return DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}