public override int GetHashCode() { return(EntityTypes.Type1.GetHashCode() ^ EntityTypes.Type2.GetHashCode() ^ CustomName.GetHashCode() ^ Level.GetHashCode() ^ XP.GetHashCode()); }
/// <summary> /// creates control user interface based on node type /// </summary> /// <param name="mainColor"></param> protected void InitializeControl(Type nodeType) { CustomNodeName.Visibility = Visibility.Collapsed; MainPanel.DataContext = NodeInstance; var ignoredProperties = nodeType.CustomAttributes .Where(a => a.AttributeType == typeof(IgnoredPropertyAttribute)) .Select(ca => ca.NamedArguments.Single(na => na.MemberName == nameof(IgnoredPropertyAttribute.Name)).TypedValue.Value as string).ToArray(); var inputProperties = nodeType.GetProperties() .Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(InputAttribute))) .Where(pi => ignoredProperties == null || !ignoredProperties.Contains(pi.Name)) .OrderBy(p => p.CustomAttributes.Single(a => a.AttributeType == typeof(InputAttribute)).NamedArguments.Single(a => a.MemberName == nameof(InputAttribute.Order)).TypedValue.Value); var outputProperties = nodeType.GetProperties() .Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(OutputAttribute))) .Where(pi => ignoredProperties == null || !ignoredProperties.Contains(pi.Name)); #region grid definition // add rows for all input properties for (var i = 0; i < inputProperties.Count(); i++) { MainPanel.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); } // number of input rows that have free output side var inputAnchorsOnly = inputProperties.Count(ip => AttributeHelper.GetValue <InputAttribute, bool>(ip, nameof(InputAttribute.AnchorOnly)) && !AttributeHelper.GetValue <InputAttribute, bool>(ip, nameof(InputAttribute.OutputAnchor))); // number of outputs that could be moved up next to inputs var outputAnchorsOnly = outputProperties.Count(op => AttributeHelper.GetValue <OutputAttribute, bool>(op, nameof(OutputAttribute.AnchorOnly))); // outputs that needs to be at bottom var outputLeft = outputProperties.Count() - outputAnchorsOnly; // number of output rows that should be added under input rows var outputRowsToAdd = outputLeft + Math.Max(0, outputAnchorsOnly - inputAnchorsOnly); // add rows for some output properties for (var i = 0; i < outputRowsToAdd; i++) { MainPanel.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); } MainPanel.RowDefinitions.Add(new RowDefinition { Height = new GridLength(AnchorSize / 2) }); // bottom #endregion #region header CustomName = AttributeHelper.GetValue <NodeInfoAttribute, string>(NodeInstance.GetType(), nameof(NodeInfoAttribute.DisplayName)) ?? NodeInstance.GetType().Name; var colorValues = BitConverter.GetBytes(CustomName.GetHashCode()); CustomColor = Color.FromArgb(0xff, colorValues[1], colorValues[2], colorValues[3]); NodeHeader.Background = new LinearGradientBrush(CustomColor, Color.Multiply(CustomColor, (float)0.5), new Point(0, 1), new Point(1, 0)); NodeTitle.Text = CustomName; #endregion #region border var border = new Border { BorderBrush = new SolidColorBrush(Colors.Black), BorderThickness = new Thickness(1, 0, 1, 1) }; Grid.SetRow(border, 1); Grid.SetColumnSpan(border, MainPanel.ColumnDefinitions.Count); Grid.SetRowSpan(border, MainPanel.RowDefinitions.Count - 1); MainPanel.Children.Add(border); #endregion var firstRow = 2; var inputRows = new bool[MainPanel.RowDefinitions.Count - 3]; var outputRows = new bool[MainPanel.RowDefinitions.Count - 3]; foreach (var inputProperty in inputProperties) { var inputAttribute = inputProperty.CustomAttributes.Single(a => a.AttributeType == typeof(InputAttribute)); var readOnly = AttributeHelper.GetValue <InputAttribute, bool>(inputProperty, nameof(InputAttribute.ReadOnly)); var anchorOnly = AttributeHelper.GetValue <InputAttribute, bool>(inputProperty, nameof(InputAttribute.AnchorOnly)); var inputAnchor = AttributeHelper.GetValue <InputAttribute, bool>(inputProperty, nameof(InputAttribute.InputAnchor)); var outputAnchor = AttributeHelper.GetValue <InputAttribute, bool>(inputProperty, nameof(InputAttribute.OutputAnchor)); var inputName = AttributeHelper.GetValue <InputAttribute, string>(inputProperty, nameof(InputAttribute.InputName)) ?? inputProperty.Name; var inputDisplayName = AttributeHelper.GetValue <InputAttribute, string>(inputProperty, nameof(InputAttribute.DisplayName)) ?? inputProperty.Name; var inputAnchorProperty = AttributeHelper.GetValue <InputAttribute, string>(inputProperty, nameof(InputAttribute.InputAnchorProperty)) ?? inputProperty.Name; var outputAnchorProperty = AttributeHelper.GetValue <InputAttribute, string>(inputProperty, nameof(InputAttribute.OutputAnchorProperty)) ?? inputProperty.Name; // next free row var row = firstRow; for (var i = 0; i < outputRows.Length; i++) { if (!inputRows[i]) { row += i; break; } } if (inputAnchor) { #region input anchor var anchor = new Rectangle { Fill = new SolidColorBrush(InputBackground), Stroke = new SolidColorBrush(Colors.Black), VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(-AnchorSize / 2, 0, 0, 0), Width = AnchorSize, Height = AnchorSize, Name = InputAnchorPrefix + inputAnchorProperty, ToolTip = inputProperty.PropertyType.Name, }; anchor.MouseEnter += HilightInputAnchorOn; anchor.MouseLeave += HilightInputAnchorOff; Grid.SetRow(anchor, row); Grid.SetColumn(anchor, 0); MainPanel.Children.Add(anchor); #endregion } #region label var label = new Label { Foreground = new SolidColorBrush(TextForeground), VerticalAlignment = VerticalAlignment.Center, Name = LabelPrefix + inputAnchorProperty, FontFamily = new FontFamily("Consolas"), Effect = LabelEffect, Content = inputDisplayName, }; Grid.SetRow(label, row); Grid.SetColumn(label, 1); if (inputAnchor && anchorOnly && outputAnchor) { label.HorizontalAlignment = HorizontalAlignment.Right; Grid.SetColumnSpan(label, 3); } else { label.HorizontalAlignment = HorizontalAlignment.Left; } MainPanel.Children.Add(label); #endregion if (!anchorOnly) { #region input element if (inputProperty.PropertyType == typeof(SolidColorBrush)) { var colorElement = new TextBox { Background = new SolidColorBrush(Colors.Black), Foreground = new SolidColorBrush(Colors.White), BorderThickness = new Thickness(1), BorderBrush = new SolidColorBrush(InputBorder), Margin = new Thickness(0, 0, 0, 0), Name = InputValuePrefix + inputName, FontFamily = new FontFamily("Consolas"), HorizontalContentAlignment = HorizontalAlignment.Center, VerticalContentAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, IsReadOnly = true, Width = 128, }; var binding = new Binding(inputProperty.Name) { Mode = BindingMode.OneWay, }; colorElement.SetBinding(TextBox.TextProperty, binding); colorElement.SetBinding(TextBox.BackgroundProperty, binding); Grid.SetRow(colorElement, row); Grid.SetColumn(colorElement, 2); MainPanel.Children.Add(colorElement); } // TODO UI INPUT CustomCheckBox //else if (inputProperty.PropertyType == typeof(bool)) //{ // var checkBox = new CheckBox // { // //Background = new SolidColorBrush(InputBackground), // //Foreground = new SolidColorBrush(TextForeground), // BorderThickness = new Thickness(1), // Name = InputValuePrefix + inputName, // FontFamily = new FontFamily("Consolas"), // HorizontalContentAlignment = HorizontalAlignment.Center, // VerticalContentAlignment = VerticalAlignment.Center, // VerticalAlignment = VerticalAlignment.Center, // HorizontalAlignment = HorizontalAlignment.Center, // }; // var binding = new Binding(inputProperty.Name) // { // Mode = BindingMode.OneWay, // }; // checkBox.SetBinding(CheckBox.IsCheckedProperty, binding); // Grid.SetRow(checkBox, row); // Grid.SetColumn(checkBox, 2); // Grid.SetColumnSpan(checkBox, mainPanel.ColumnDefinitions.Count - 1); // mainPanel.Children.Add(checkBox); //} else { var textbox = new TextBox { Foreground = new SolidColorBrush(TextForeground), BorderBrush = new SolidColorBrush(InputBorder), Background = new SolidColorBrush(InputBackground), VerticalAlignment = VerticalAlignment.Center, TextAlignment = TextAlignment.Right, Margin = new Thickness(0, 0, 4, 0), Name = InputValuePrefix + inputName, IsReadOnly = readOnly, FontFamily = new FontFamily("Consolas"), TextWrapping = TextWrapping.Wrap, VerticalScrollBarVisibility = ScrollBarVisibility.Auto, MaxHeight = 128, MaxWidth = 256, }; var binding = new Binding(inputProperty.Name) { Mode = readOnly ? BindingMode.OneWay : BindingMode.TwoWay, ValidatesOnExceptions = true }; if (inputProperty.PropertyType == typeof(double)) { textbox.MinWidth = 64; binding.StringFormat = "{0:F" + DecimalPrecision + "}"; } else if (inputProperty.PropertyType == typeof(int)) { textbox.MinWidth = 64; } else if (inputProperty.PropertyType == typeof(string)) { textbox.MinWidth = 128; textbox.TextAlignment = TextAlignment.Left; textbox.TextWrapping = TextWrapping.NoWrap; } textbox.SetBinding(TextBox.TextProperty, binding); Grid.SetRow(textbox, row); Grid.SetColumn(textbox, 2); MainPanel.Children.Add(textbox); } #endregion outputRows[row - firstRow] = true; } if (outputAnchor) { #region output anchor var anchor = new Rectangle { Fill = new SolidColorBrush(CustomColor), Stroke = new SolidColorBrush(Colors.Black), VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(0, 0, -AnchorSize / 2, 0), Width = AnchorSize, Height = AnchorSize, Name = OutputAnchorPrefix + outputAnchorProperty, ToolTip = inputProperty.PropertyType.Name, }; anchor.MouseEnter += HilightOutputAnchorOn; anchor.MouseLeave += HilightOutputAnchorOff; Grid.SetRow(anchor, row); Grid.SetColumn(anchor, MainPanel.ColumnDefinitions.Count - 1); MainPanel.Children.Add(anchor); #endregion outputRows[row - firstRow] = true; } inputRows[row - firstRow] = true; } foreach (var outputProperty in outputProperties) { var outputAttribute = outputProperty.CustomAttributes.Single(a => a.AttributeType == typeof(OutputAttribute)); var readOnly = AttributeHelper.GetValue <OutputAttribute, bool>(outputProperty, nameof(OutputAttribute.ReadOnly)); var anchorOnly = AttributeHelper.GetValue <OutputAttribute, bool>(outputProperty, nameof(OutputAttribute.AnchorOnly)); var noAnchor = AttributeHelper.GetValue <OutputAttribute, bool>(outputProperty, nameof(OutputAttribute.NoAnchor)); var outputDisplayName = AttributeHelper.GetValue <OutputAttribute, string>(outputProperty, nameof(OutputAttribute.DisplayName)) ?? outputProperty.Name; var outputAnchorProperty = AttributeHelper.GetValue <OutputAttribute, string>(outputProperty, nameof(OutputAttribute.OutputAnchorProperty)) ?? outputProperty.Name; // next free row var row = firstRow; for (var i = 0; i < outputRows.Length; i++) { if (!outputRows[i] && (anchorOnly || !inputRows[i])) { row += i; break; } } if (!anchorOnly) { #region output element if (outputProperty.PropertyType == typeof(BitmapSource)) { var imageBorder = new Border { BorderThickness = new Thickness(1), BorderBrush = new SolidColorBrush(InputBorder), }; var image = new Image(); imageBorder.Child = image; image.SetBinding(Image.SourceProperty, new Binding(outputProperty.Name) { Mode = BindingMode.OneWay }); var widthBinding = AttributeHelper.GetValue <ImageBindingsAttribute, string>(outputProperty, nameof(ImageBindingsAttribute.Width)); var heightBinding = AttributeHelper.GetValue <ImageBindingsAttribute, string>(outputProperty, nameof(ImageBindingsAttribute.Height)); if (!string.IsNullOrEmpty(widthBinding) && !string.IsNullOrEmpty(heightBinding)) { image.SetBinding(Image.WidthProperty, new Binding(widthBinding) { Mode = BindingMode.OneWay }); image.SetBinding(Image.HeightProperty, new Binding(heightBinding) { Mode = BindingMode.OneWay }); } Grid.SetRow(imageBorder, row); Grid.SetColumn(imageBorder, 1); Grid.SetColumnSpan(imageBorder, MainPanel.ColumnDefinitions.Count - 2); MainPanel.Children.Add(imageBorder); } else { var textbox = new TextBox { Foreground = new SolidColorBrush(TextForeground), BorderBrush = new SolidColorBrush(InputBorder), Background = new SolidColorBrush(InputBackground), VerticalAlignment = VerticalAlignment.Center, TextAlignment = outputProperty.PropertyType == typeof(string) ? TextAlignment.Left : TextAlignment.Right, Margin = new Thickness(0, 0, 4, 0), Name = OutputValuePrefix + outputAnchorProperty, FontFamily = new FontFamily("Consolas"), IsReadOnly = readOnly, TextWrapping = TextWrapping.Wrap, VerticalScrollBarVisibility = ScrollBarVisibility.Auto, MaxHeight = 128, MaxWidth = 256, }; var binding = new Binding(outputProperty.Name) { Mode = BindingMode.TwoWay, ValidatesOnExceptions = true }; if (outputProperty.PropertyType == typeof(double)) { binding.StringFormat = "{0:F" + DecimalPrecision + "}"; } textbox.SetBinding(TextBox.TextProperty, binding); Grid.SetRow(textbox, row); Grid.SetColumn(textbox, 2); MainPanel.Children.Add(textbox); } #endregion } #region label var label = new Label { Foreground = new SolidColorBrush(TextForeground), VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Right, Name = LabelPrefix + outputAnchorProperty, FontFamily = new FontFamily("Consolas"), Effect = LabelEffect, Content = outputDisplayName, }; Grid.SetRow(label, row); if (anchorOnly) { Grid.SetColumn(label, 0); Grid.SetColumnSpan(label, MainPanel.ColumnDefinitions.Count - 1); } else { Grid.SetColumn(label, MainPanel.ColumnDefinitions.Count - 2); } MainPanel.Children.Add(label); #endregion if (!noAnchor) { #region output anchor var anchor = new Rectangle { Fill = new SolidColorBrush(CustomColor), Stroke = new SolidColorBrush(Colors.Black), VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(0, 0, -8, 0), Width = AnchorSize, Height = AnchorSize, Name = OutputAnchorPrefix + outputAnchorProperty, ToolTip = outputProperty.PropertyType.Name, }; anchor.MouseEnter += HilightOutputAnchorOn; anchor.MouseLeave += HilightOutputAnchorOff; Grid.SetRow(anchor, row); Grid.SetColumn(anchor, MainPanel.ColumnDefinitions.Count - 1); MainPanel.Children.Add(anchor); #endregion } outputRows[row - firstRow] = true; } //MainPanel.RowDefinitions.Add(new RowDefinition { Height = new GridLength(30) }); //var customDouble = new CustomFloatingInput(); //Grid.SetRow(customDouble, MainPanel.RowDefinitions.Count - 1); //Grid.SetColumn(customDouble, 1); //Grid.SetColumnSpan(customDouble, 2); //MainPanel.Children.Add(customDouble); //MainPanel.RowDefinitions.Add(new RowDefinition { Height = new GridLength(30) }); //var customInteger = new CustomIntegerInput(); //Grid.SetRow(customInteger, MainPanel.RowDefinitions.Count - 1); //Grid.SetColumn(customInteger, 1); //Grid.SetColumnSpan(customInteger, 2); //MainPanel.Children.Add(customInteger); //MainPanel.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto, MinHeight = 30 }); //var customText = new CustomTextInput(); //Grid.SetRow(customText, MainPanel.RowDefinitions.Count - 1); //Grid.SetColumn(customText, 1); //Grid.SetColumnSpan(customText, 2); //MainPanel.Children.Add(customText); }