Disposal mailing (#2194)
* Implement device networking * Implement device configuration menu * Fix device network * Implement disposal mailing unit * Implement base network connection Implement wired and wireless network connection Implement device network metadata * Fix dereference null error * Fix wired network null checks * Change BaseNetworks enum to NetworkUtils class Add PingResponse function to NetworkUtils Change device network file structure * Add doc comments * Apply suggestions from code review Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com> * Add tag validation to disposal mailing unit * Add tag validation to the mailing unit component * Address reviews Change WiredNetwork can connect check Change device networking string literals to constants * Address reviews Revert changes to PowerProvider and PowerReceiver Add new NodeGroup WELP * Fix recursive access to Owner property * Integrate suggested changes * Fix TryGetWireNet acting on NullPowerProvider Fix network connections not checking if their owner has been deleted * Close device network connection when the owning entity got deleted Fix mailing unit not closing the device network connection on remove * Remove GetWireNet from NullPowerProvider Co-authored-by: Julian Giebel <j.giebel@netrocks.info> Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using Content.Client.GameObjects.Components.Disposal;
|
||||
using Content.Client.GameObjects.Components.MedicalScanner;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
@@ -14,7 +14,8 @@ namespace Content.Client.GameObjects.Components.Body
|
||||
public bool CanDrop(CanDropEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.Target.HasComponent<DisposalUnitComponent>() ||
|
||||
eventArgs.Target.HasComponent<MedicalScannerComponent>())
|
||||
eventArgs.Target.HasComponent<MedicalScannerComponent>() ||
|
||||
eventArgs.Target.HasComponent<DisposalMailingUnitComponent>())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using static Content.Shared.GameObjects.Components.SharedConfigurationComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Wires
|
||||
{
|
||||
public class ConfigurationBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
public Regex Validation { get; internal set; }
|
||||
|
||||
public ConfigurationBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
private ConfigurationMenu _menu;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_menu = new ConfigurationMenu(this);
|
||||
|
||||
_menu.OnClose += Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
_menu.Populate(state as ConfigurationBoundUserInterfaceState);
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
base.ReceiveMessage(message);
|
||||
if (message is ValidationUpdateMessage msg)
|
||||
{
|
||||
Validation = new Regex(msg.ValidationString, RegexOptions.Compiled);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendConfiguration(Dictionary<string, string> config)
|
||||
{
|
||||
SendMessage(new ConfigurationUpdatedMessage(config));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
_menu.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
using System.Collections.Generic;
|
||||
using Namotion.Reflection;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using static Content.Shared.GameObjects.Components.SharedConfigurationComponent;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Wires
|
||||
{
|
||||
public class ConfigurationMenu : SS14Window
|
||||
{
|
||||
public ConfigurationBoundUserInterface Owner { get; }
|
||||
|
||||
private readonly VBoxContainer _baseContainer;
|
||||
private readonly VBoxContainer _column;
|
||||
private readonly HBoxContainer _row;
|
||||
|
||||
private readonly List<(string name, LineEdit input)> _inputs;
|
||||
|
||||
protected override Vector2? CustomSize => (300, 250);
|
||||
|
||||
public ConfigurationMenu(ConfigurationBoundUserInterface owner)
|
||||
{
|
||||
Owner = owner;
|
||||
|
||||
_inputs = new List<(string name, LineEdit input)>();
|
||||
|
||||
Title = Loc.GetString("Device Configuration");
|
||||
|
||||
var margin = new MarginContainer
|
||||
{
|
||||
MarginBottomOverride = 8,
|
||||
MarginLeftOverride = 8,
|
||||
MarginRightOverride = 8,
|
||||
MarginTopOverride = 8
|
||||
};
|
||||
|
||||
_baseContainer = new VBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
};
|
||||
|
||||
_column = new VBoxContainer
|
||||
{
|
||||
SeparationOverride = 16,
|
||||
SizeFlagsVertical = SizeFlags.Fill
|
||||
};
|
||||
|
||||
_row = new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 16,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
};
|
||||
|
||||
var buttonRow = new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
};
|
||||
|
||||
var spacer1 = new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Expand
|
||||
};
|
||||
|
||||
var spacer2 = new HBoxContainer()
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Expand
|
||||
};
|
||||
|
||||
var confirmButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("Confirm"),
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||
};
|
||||
|
||||
confirmButton.OnButtonUp += OnConfirm;
|
||||
buttonRow.AddChild(spacer1);
|
||||
buttonRow.AddChild(confirmButton);
|
||||
buttonRow.AddChild(spacer2);
|
||||
|
||||
var outerColumn = new ScrollContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
ModulateSelfOverride = Color.FromHex("#202025")
|
||||
};
|
||||
|
||||
margin.AddChild(_column);
|
||||
outerColumn.AddChild(margin);
|
||||
_baseContainer.AddChild(outerColumn);
|
||||
_baseContainer.AddChild(buttonRow);
|
||||
Contents.AddChild(_baseContainer);
|
||||
}
|
||||
|
||||
public void Populate(ConfigurationBoundUserInterfaceState state)
|
||||
{
|
||||
_column.Children.Clear();
|
||||
_inputs.Clear();
|
||||
|
||||
foreach (var field in state.Config)
|
||||
{
|
||||
var margin = new MarginContainer
|
||||
{
|
||||
MarginRightOverride = 8
|
||||
};
|
||||
|
||||
var label = new Label
|
||||
{
|
||||
Name = field.Key,
|
||||
Text = field.Key + ":",
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsStretchRatio = .2f,
|
||||
CustomMinimumSize = new Vector2(60, 0)
|
||||
};
|
||||
|
||||
var input = new LineEdit
|
||||
{
|
||||
Name = field.Key + "-input",
|
||||
Text = field.Value,
|
||||
IsValid = Validate,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsStretchRatio = .8f
|
||||
};
|
||||
|
||||
_inputs.Add((field.Key, input));
|
||||
|
||||
var row = new HBoxContainer();
|
||||
CopyProperties(_row, row);
|
||||
|
||||
margin.AddChild(label);
|
||||
row.AddChild(margin);
|
||||
row.AddChild(input);
|
||||
_column.AddChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConfirm(ButtonEventArgs args)
|
||||
{
|
||||
var config = GenerateDictionary<string, LineEdit>(_inputs, "Text");
|
||||
|
||||
Owner.SendConfiguration(config);
|
||||
Close();
|
||||
}
|
||||
|
||||
private bool Validate(string value)
|
||||
{
|
||||
return Owner.Validation == null || Owner.Validation.IsMatch(value);
|
||||
}
|
||||
|
||||
private Dictionary<string, TConfig> GenerateDictionary<TConfig, TInput>(List<(string name, TInput input)> inputs, string propertyName) where TInput : Control
|
||||
{
|
||||
var dictionary = new Dictionary<string, TConfig>();
|
||||
foreach (var input in inputs)
|
||||
{
|
||||
var value = input.input.TryGetPropertyValue<TConfig>(propertyName);
|
||||
dictionary.Add(input.name, value);
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private static void CopyProperties<T>(T from, T to) where T : Control
|
||||
{
|
||||
foreach (var property in from.AllAttachedProperties)
|
||||
{
|
||||
to.SetValue(property.Key, property.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#nullable enable
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalMailingUnitComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Disposal
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="DisposalMailingUnitWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class DisposalMailingUnitBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private DisposalMailingUnitWindow? _window;
|
||||
|
||||
public DisposalMailingUnitBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
private void ButtonPressed(UiButton button)
|
||||
{
|
||||
SendMessage(new UiButtonPressedMessage(button));
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new DisposalMailingUnitWindow();
|
||||
|
||||
_window.OpenCentered();
|
||||
_window.OnClose += Close;
|
||||
|
||||
_window.Eject.OnPressed += _ => ButtonPressed(UiButton.Eject);
|
||||
_window.Engage.OnPressed += _ => ButtonPressed(UiButton.Engage);
|
||||
_window.Power.OnPressed += _ => ButtonPressed(UiButton.Power);
|
||||
_window.TargetListContainer.OnItemSelected += TargetSelected;
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (!(state is DisposalMailingUnitBoundUserInterfaceState cast))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_window?.UpdateState(cast);
|
||||
}
|
||||
|
||||
private void TargetSelected(ItemList.ItemListSelectedEventArgs item)
|
||||
{
|
||||
SendMessage(new UiTargetUpdateMessage(_window?.TargetList[item.ItemIndex]));
|
||||
//(ノ°Д°)ノ︵ ┻━┻
|
||||
if (_window != null) _window.Engage.Disabled = false;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Content.Shared.GameObjects.Components.Disposal;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Disposal
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedDisposalMailingUnitComponent))]
|
||||
public class DisposalMailingUnitComponent : SharedDisposalMailingUnitComponent
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
using Content.Shared.GameObjects.Components.Disposal;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using System.Collections.Generic;
|
||||
using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalMailingUnitComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Disposal
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side UI used to control a <see cref="SharedDisposalMailingUnitComponent"/>
|
||||
/// </summary>
|
||||
public class DisposalMailingUnitWindow : SS14Window
|
||||
{
|
||||
private readonly Label _unitState;
|
||||
private readonly ProgressBar _pressureBar;
|
||||
private readonly Label _pressurePercentage;
|
||||
public readonly Button Engage;
|
||||
public readonly Button Eject;
|
||||
public readonly Button Power;
|
||||
|
||||
public readonly ItemList TargetListContainer;
|
||||
public List<string> TargetList;
|
||||
private readonly Label _tagLabel;
|
||||
|
||||
protected override Vector2? CustomSize => (460, 220);
|
||||
|
||||
public DisposalMailingUnitWindow()
|
||||
{
|
||||
TargetList = new List<string>();
|
||||
Contents.AddChild(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new MarginContainer
|
||||
{
|
||||
MarginLeftOverride = 8,
|
||||
MarginRightOverride = 8,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label {Text = Loc.GetString("State: ")},
|
||||
new Control {CustomMinimumSize = (4, 0)},
|
||||
(_unitState = new Label {Text = Loc.GetString("Ready")})
|
||||
}
|
||||
},
|
||||
new Control {CustomMinimumSize = (0, 10)},
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Label {Text = Loc.GetString("Pressure:")},
|
||||
new Control {CustomMinimumSize = (4, 0)},
|
||||
(_pressureBar = new ProgressBar
|
||||
{
|
||||
CustomMinimumSize = (100, 20),
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
MinValue = 0,
|
||||
MaxValue = 1,
|
||||
Page = 0,
|
||||
Value = 0.5f,
|
||||
Children =
|
||||
{
|
||||
(_pressurePercentage = new Label())
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
new Control {CustomMinimumSize = (0, 10)},
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Label {Text = Loc.GetString("Handle:")},
|
||||
new Control {
|
||||
CustomMinimumSize = (4, 0),
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
},
|
||||
(Engage = new Button
|
||||
{
|
||||
CustomMinimumSize = (16, 0),
|
||||
Text = Loc.GetString("Engage"),
|
||||
ToggleMode = true,
|
||||
Disabled = true
|
||||
})
|
||||
}
|
||||
},
|
||||
new Control {CustomMinimumSize = (0, 10)},
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Label {Text = Loc.GetString("Eject:")},
|
||||
new Control {
|
||||
CustomMinimumSize = (4, 0),
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
},
|
||||
(Eject = new Button {
|
||||
CustomMinimumSize = (16, 0),
|
||||
Text = Loc.GetString("Eject Contents"),
|
||||
//SizeFlagsHorizontal = SizeFlags.ShrinkEnd
|
||||
})
|
||||
}
|
||||
},
|
||||
new Control {CustomMinimumSize = (0, 10)},
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
(Power = new CheckButton {Text = Loc.GetString("Power")}),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
new MarginContainer
|
||||
{
|
||||
MarginLeftOverride = 12,
|
||||
MarginRightOverride = 8,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new VBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
Children =
|
||||
{
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = Loc.GetString("Select a destination:")
|
||||
}
|
||||
}
|
||||
},
|
||||
new Control { CustomMinimumSize = new Vector2(0, 8) },
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
(TargetListContainer = new ItemList
|
||||
{
|
||||
SelectMode = ItemList.ItemListSelectMode.Single,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SizeFlagsVertical = SizeFlags.FillExpand
|
||||
})
|
||||
}
|
||||
},
|
||||
new PanelContainer
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat
|
||||
{
|
||||
BackgroundColor = Color.FromHex("#ACBDBA")
|
||||
},
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
CustomMinimumSize = new Vector2(0, 1),
|
||||
},
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new VBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new MarginContainer
|
||||
{
|
||||
MarginLeftOverride = 4,
|
||||
Children =
|
||||
{
|
||||
new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = Loc.GetString("This unit:")
|
||||
},
|
||||
new Control
|
||||
{
|
||||
CustomMinimumSize = new Vector2(4, 0)
|
||||
},
|
||||
(_tagLabel = new Label
|
||||
{
|
||||
Text = "-",
|
||||
SizeFlagsVertical = SizeFlags.ShrinkEnd
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdatePressureBar(float pressure)
|
||||
{
|
||||
_pressureBar.Value = pressure;
|
||||
|
||||
var normalized = pressure / _pressureBar.MaxValue;
|
||||
|
||||
const float leftHue = 0.0f; // Red
|
||||
const float middleHue = 0.066f; // Orange
|
||||
const float rightHue = 0.33f; // Green
|
||||
const float saturation = 1.0f; // Uniform saturation
|
||||
const float value = 0.8f; // Uniform value / brightness
|
||||
const float alpha = 1.0f; // Uniform alpha
|
||||
|
||||
// These should add up to 1.0 or your transition won't be smooth
|
||||
const float leftSideSize = 0.5f; // Fraction of _chargeBar lerped from leftHue to middleHue
|
||||
const float rightSideSize = 0.5f; // Fraction of _chargeBar lerped from middleHue to rightHue
|
||||
|
||||
float finalHue;
|
||||
if (normalized <= leftSideSize)
|
||||
{
|
||||
normalized /= leftSideSize; // Adjust range to 0.0 to 1.0
|
||||
finalHue = MathHelper.Lerp(leftHue, middleHue, normalized);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalized = (normalized - leftSideSize) / rightSideSize; // Adjust range to 0.0 to 1.0.
|
||||
finalHue = MathHelper.Lerp(middleHue, rightHue, normalized);
|
||||
}
|
||||
|
||||
// Check if null first to avoid repeatedly creating this.
|
||||
_pressureBar.ForegroundStyleBoxOverride ??= new StyleBoxFlat();
|
||||
|
||||
var foregroundStyleBoxOverride = (StyleBoxFlat) _pressureBar.ForegroundStyleBoxOverride;
|
||||
foregroundStyleBoxOverride.BackgroundColor =
|
||||
Color.FromHsv(new Vector4(finalHue, saturation, value, alpha));
|
||||
|
||||
var percentage = pressure / _pressureBar.MaxValue * 100;
|
||||
_pressurePercentage.Text = $" {percentage:0}%";
|
||||
}
|
||||
|
||||
public void UpdateState(DisposalMailingUnitBoundUserInterfaceState state)
|
||||
{
|
||||
Title = state.UnitName;
|
||||
_unitState.Text = state.UnitState;
|
||||
UpdatePressureBar(state.Pressure);
|
||||
Power.Pressed = state.Powered;
|
||||
Engage.Pressed = state.Engaged;
|
||||
PopulateTargetList(state.Tags);
|
||||
_tagLabel.Text = state.Tag;
|
||||
TargetList = state.Tags;
|
||||
}
|
||||
|
||||
private void PopulateTargetList(List<string> tags)
|
||||
{
|
||||
TargetListContainer.Clear();
|
||||
foreach (var target in tags)
|
||||
{
|
||||
TargetListContainer.AddItem(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user