Reference where non should be - c#

I have a class called Board. It has multiple columns and you can add Stones to a column by Calling AddStoneToColumn(column c). The method shouldnt modify the objet itselft but only create a new Board Object with the added stone but somehow it keeps changing itself too.
Heres my relevant Code:
public Board AddStoneToColumn(int column)
{
Board resultBoard = new Board(this);
Boolean isPlaced = false;
for (int i = 0; i < height; i++)
{
if (resultBoard.GetStone(column, i) == StoneEnum.EMPTY)
{
resultBoard.SetExactCoords(column, i, turn);
isPlaced = true;
break;
}
}
if (!isPlaced)
{
throw new InvalidOperationException("Spalte voll");
}
if (turn == StoneEnum.BLUE)
resultBoard.turn = StoneEnum.RED;
if (turn == StoneEnum.RED)
resultBoard.turn = StoneEnum.BLUE;
return resultBoard;
}
private void SetExactCoords(int x, int y, StoneEnum stone)
{
if (stone == StoneEnum.EMPTY)
throw new NotSupportedException("Empty stone ??");
this.stones[x, y] = stone;
}
public Board(Board board)
{
this.stones = board.stones;
this.turn = board.turn;
}

You are only copying references in your cloning constructor, not creating a copy of the data. You will have to duplicate those arrays/collections.

Maybe you can use a struct instead of a class?
But for your example, i would use
ICloneable Interface.
Also, you can watch this discussion too.

Related

How do I retrieve data from a child object in a base object array?

Say I have a GameObject array with child objects inside of it:
GameObjects = new List<GameObject>
{
new Tile(0, 0, new int[] { 1, 2, 3, 0 }),
new BuyTile(1, 0),
new BuyTile(0, 1),
new BuyTile(-1, 0),
new BuyTile(0, -1)
};
And I want to access a property in a Tile object in this array.
public void UpdateResources()
{
for (int i = 0; i < GameObjects.Count; i++)
{
if (GameObjects[i] is Tile)
{
/* I want to read a property of the Tile here, and it's not in the abstract class
* GameObject.
*/
}
}
}
How do I do so?
I couldn't find anything myself about this issue, but if someone has a link to another related question I will gladly accept it.
public void UpdateResources()
{
for (int i = 0; i < GameObjects.Count; i++)
{
if (GameObjects[i] is Tile t)
{
t.X // <- read property
}
}
}
You can use as operator and null check:
for (int i = 0; i < GameObjects.Count; i++)
{
var tile = GameObjects[i] as Tile;
if (tile != null)
{
// use tile
}
}
If your version of unity supports C# 7.0 you can use is operator with the type pattern:
for (int i = 0; i < GameObjects.Count; i++)
{
if (GameObjects[i] is Tile tile)
{
// use tile
}
}
You can try Linq:
public void UpdateResources() {
foreach (Tile tile in GameObjects.OfType<Tile>()) {
//TODO: put relevant code here, e.g.
// tile.SomeProperty = tile.SomeProperty - 5;
}
}

How to Clone a Windows Forms Controls even with non-Serializable properties?

How to Clone or Serialize a Windows Forms Control?
When I am trying to Clone windows forms controls using this code "CloneControl(Control ct1)", it allows me to duplicate controls with some Serializable properties, not with all properties.
public Form1()
{
InitializeComponent();
Columns = new DataGridViewTextBoxColumn[2];
for (int i = 0; i < 2; i++)
{
Columns[i] = new System.Windows.Forms.DataGridViewTextBoxColumn();
//
// Columns[i]
//
Columns[i].HeaderText = "j" + (i + 1);
Columns[i].Name = "Column" + (i + 1);
Columns[i].Width = 50;
}
dataGridView1 = new System.Windows.Forms.DataGridView();
dataGridView1.Name = "dataGridView1";
dataGridView1.Location = new System.Drawing.Point(100, 100);
dataGridView1.RowHeadersWidth = 50;
dataGridView1.RowTemplate.Height = 25;
dataGridView1.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
dataGridView1.Anchor = System.Windows.Forms.AnchorStyles.None;
dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Columns.AddRange(Columns);
dataGridView1.TabIndex = 3;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
dataGridView1.Rows[0].HeaderCell.Value = "i" + 1;
dataGridView1.Rows[1].HeaderCell.Value = "i" + 2;
dataGridView1.Rows[0].Cells[0].Value = "value1";
Controls.Add(dataGridView1);
Control cloned1 = CloneControl(dataGridView1);
cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
Controls.Add(cloned1);
cloned1.Show();
}
public Control CloneControl(Control ct1)
{
Hashtable PropertyList = new Hashtable();
PropertyDescriptorCollection Properties = TypeDescriptor.GetProperties(ct1);
Assembly controlAsm = Assembly.LoadWithPartialName(ct1.GetType().Namespace);
Type controlType = controlAsm.GetType(ct1.GetType().Namespace + "." + ct1.GetType().Name);
Control cloned1 = (Control)Activator.CreateInstance(controlType);
foreach (PropertyDescriptor pr1 in Properties)
{
if (pr1.PropertyType.IsSerializable)
{
PropertyList.Add(pr1.Name, pr1.GetValue(ct1));
}
if (PropertyList.Contains(pr1.Name))
{
try
{
Object obj = PropertyList[pr1.Name];
pr1.SetValue(cloned1, obj);
}
catch (Exception ex)
{
}
}
}
return ct2;
}
If you run the code... the you will get
As you can see in the main method I create a clone of dataGridView1, which has a few properties.
And actually each cell value is null in a cloned dataGridView.
Also size of a columns are not cloned!
You may have a question: if Visual Studio or SharpDeveloper as IDE which is written in C# can handle this problem, then it might be possible to write that kind of code! Right?
In Visual Studio When you are trying drag and drop controls, or copy and paste controls, it not only duplicates that controls with all properties (including Serializable or non-Serializable) but also it changes the name of control itself from "dataGridView1" to "dataGridView2" as well as in SharpDeveloper!
What should I do?
What kind of method should I create?
Maybe another control has a many non-Serializable properties!
How to duplicate all of them?
Please anyone.....
Like #Hans mentioned in the comment, Clone is not that easy. If you want to get some identical controls with only a bit different, you'd better use a function to define general behavior and pass the different properties in as parameters. For example, we define a function with some general properties which apply to DataGridView:
private void InitDataGridView(DataGridView dataGridView, string name)
{
dataGridView.Name = name;
// configure other properties here
dataGridView.Location = new System.Drawing.Point(100, 100);
dataGridView.RowHeadersWidth = 50;
dataGridView.RowTemplate.Height = 25;
dataGridView.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
dataGridView.Anchor = System.Windows.Forms.AnchorStyles.None;
dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
// remember to initialize your columns, or pass it in as a parameter
dataGridView.Columns.AddRange(Columns);
dataGridView.AllowUserToAddRows = false;
dataGridView.Rows.Add();
dataGridView.Rows.Add();
dataGridView.Rows[0].HeaderCell.Value = "i" + 1;
dataGridView.Rows[1].HeaderCell.Value = "i" + 2;
dataGridView.Rows[0].Cells[0].Value = "value1";
}
public Form1()
{
InitializeComponent();
var dataGridView1 = new DataGridView();
var dataGridView2 = new DataGridView();
InitDataGridView(dataGridView1, "dataGridView1");
InitDataGridView(dataGridView2, "dataGridView2");
}
IDE (e.g. Visual Studio) is using PropertyDescriptors, DesignerSerializationVisibility and ShouldSerializeValue, but DataGrid Rows are something special, because you cannot add them at design time! IDE cannot copy something that is not there, so, the solution must be different (if you want to clone controls beyond what IDE/Designer can do - see other answers and comments for this). Try my code (everything except grid rows got cloned without the extra check - the columns got cloned).
foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
if(!pd.ShouldSerializeValue(src)) {
if(src is DataGridView && pd.Name == "Rows")
CopyDataGridRows((DataGridView)src, (DataGridView)dst);
continue; }
Note: The above can be done better (by check for the class at the end), but is as it is to be obvious.
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CloneControls {
public partial class Form1: Form {
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) {
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
foreach(Control c in splitContainer1.Panel1.Controls)
splitContainer1.Panel2.Controls.Add((Control)Clone(c));
}
static object Clone(object o) {
return Copy(o, Activator.CreateInstance(o.GetType()));
}
static object Copy(object src, object dst) {
IList list = src as IList;
if(list != null) {
IList to = dst as IList;
foreach(var x in list)
to.Add(Clone(x));
return dst; }
foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
if(!pd.ShouldSerializeValue(src)) {
if(src is DataGridView && pd.Name == "Rows")
CopyDataGridRows((DataGridView)src, (DataGridView)dst);
continue; }
switch(pd.SerializationVisibility) {
default: continue;
case DesignerSerializationVisibility.Visible:
if(pd.IsReadOnly) continue;
pd.SetValue(dst, pd.GetValue(src));
continue;
case DesignerSerializationVisibility.Content:
Copy(pd.GetValue(src), pd.GetValue(dst));
continue;
}
}
return dst;
}
static void CopyDataGridRows(DataGridView src, DataGridView dst) {
foreach(DataGridViewRow row in src.Rows)
if(!row.IsNewRow) dst.Rows.Add((DataGridViewRow)Clone(row));
}
}
}
I think I made more better method here.
This Method at first checks interface of property: if it is ICollection then it does the first job.
After this one loop ends in the method "DeepClone()", then it is necessary to do another loop without checking PropertyType Interface... I mean I could not mix these two operation into one loop?!
Also You can detect that there will be some kind of Run-time Exceptions and for this reason I put this code into try-catch block...
Control cloned1 = (Control)DeepClone(dataGridView1);
cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
Controls.Add(cloned1);
cloned1.Show();
public dynamic DeepClone(dynamic ob1)
{
dynamic ob2 = null;
if (ob1.GetType().IsSerializable && !ob1.GetType().IsArray)
{
if (ob1 != null)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, ob1);
ms.Position = 0;
ob2 = formatter.Deserialize(ms);
}
}
}
else
{
if (ob1.GetType().IsArray)
{
var r1 = ob1.Rank;
object[] d1 = new object[r1];
long[] V1 = new long[r1];
for (int i = 0; i < r1; i++)
{
V1[i] = 0;
d1[i] = ob1.GetUpperBound(i) + 1;
}
ob2 = Activator.CreateInstance(ob1.GetType(), d1);
for (long i = 0; i <= ob2.Length; i++)
{
ob2.SetValue(DeepClone(ob1.GetValue(V1)), V1);
for (int j = 0; j <= V1.GetUpperBound(0); j++)
{
if (V1[j] < ob2.GetUpperBound(j))
{
V1[j]++;
break;
}
else
{
V1[j] = 0;
}
}
}
}
else
{
PropertyInfo[] P1 = ob1.GetType().GetProperties();
ob2 = Activator.CreateInstance(ob1.GetType());
foreach (PropertyInfo p1 in P1)
{
try
{
if (p1.PropertyType.GetInterface("System.Collections.ICollection", true) != null)
{
dynamic V2 = p1.GetValue(ob1) as IEnumerable;
MethodInfo gm1 = p1.PropertyType.GetMethods().Where(m => m.Name == "Add").Where(p => p.GetParameters().Count() == 1).First(f => V2[0].GetType().IsSubclassOf(f.GetParameters()[0].ParameterType) || f.GetParameters()[0].ParameterType == V2[0].GetType());
if (V2[0].GetType().IsSubclassOf(gm1.GetParameters()[0].ParameterType) || gm1.GetParameters()[0].ParameterType == V2[0].GetType())
{
for (int i = 0; i < V2.Count; i++)
{
dynamic V3 = DeepClone(V2[i]);
gm1.Invoke(p1.GetValue(ob2), new[] {V3});
}
}
}
}
catch (Exception ex)
{
}
}
foreach (PropertyInfo p1 in P1)
{
try
{
if (p1.PropertyType.IsSerializable && p1.CanWrite)
{
var v2 = p1.GetValue(ob1);
p1.SetValue(ob2, v2);
}
if (!p1.PropertyType.IsSerializable && p1.CanWrite)
{
dynamic V2 = p1.GetValue(ob1);
if (p1.PropertyType.GetMethod("Clone") != null)
{
dynamic v1 = V2.Clone();
p1.SetValue(ob2, v1);
}
}
}
catch (Exception ex)
{
}
}
}
}
return ob2;
}
You may say that this Method does not copy some kind of property, But it does copy of main properties and the Cloned control will look like an original control!
Trying to clone a control is overkill except if you really need a totally generic control clone method. Most of the time, you only need to clone a specific control and you have an easy access to the code that created it (see the Form designer generated code, and the setup code you wrote yourself).
But nevertheless, I once used a trick to duplicate many controls at once in order to fill the new tabs of a TabControl, choosing one out of ten tab designs.
I also wanted to use the Form design tool of the C# IDE to edit and modify the 10 template.
So, besides my Tab control form, and using the VS IDE, I created 10 "control factory dummy forms" in my project. I put a dummy Panel control in each of it.
Each time I had to dynamically create a new Tab, I simply instantiated a new dummy window of the desired style. Then I simply moved the Parent pane to my ControlTab (using the Controls.Add() method of the new tab).
This way, you must link the event handlers after the Tab creation (after the controls move). And the event handler's code should be written in you main window class, otherwise you will have "this" reference problems.
Obviously, you will have to store control references somewhere, to be able to access them. The easiest way to do this is to just keep track of each "dummy template Form" you instantiate and to set the "modifier" of your controls to be "public". You can use the Tag property of the destination tab page to store that reference. But, to avoid many casts, it is better to declare an array of each form class, and to store the references there.

Trying to select from a list the first previous eligible index

I have a List<List<Object>> in which one of these objects has the property isCurrentlySelected = true. This nested list represents a grid of these objects that might be constructed in any configuration (i.e. the grid may be any dimensions, and may even be jagged).
Now, some of these objects have the property isSelectable = false, so I'm trying to create a method which takes a single parameter for "direction" and returns the first eligible index in the specified direction from the one currently marked as selected.
So far I've only been able to do this using several nested for loops and if-else statements, and even then, it will only work for one direction. I'm wondering if there's a more elegant way to check for the first eligible element, preferably using a single method.
Thanks in advance for any help,
~KWiP
EDIT: with code sample
So I have the Menu class:
public class Menu
{
public int x;
public int y;
public int width;
public int height;
public int lineHeight;
public float menuTimer = 0.0f;
public bool menuKeysPressed = false;
public List<List<Selection>> selections = new List<List<Selection>>();
public int selectedList = 0;
public int selectedItem = 0;
in which is the child class Selection:
public class Selection
{
public int x;
public int y;
public bool isCurrentlySelected = false;
public bool isSelectable = true;
public Color selectedColor = Color.White;
public Color unselectedColor = Color.Gray;
public bool isNonText = false;
public string displayText = "";
public int textSize;
public Selection(int xPos, int yPos, string text, int size, bool selectable)
{
x = xPos;
y = yPos;
displayText = text;
textSize = size;
if (!selectable)
{
isCurrentlySelected = false;
}
}
}
Each Selection in a Menu object has X and Y coordinates in the form of its indices in the nested lists found in Menu.selections. In each Menu, there is typically exactly one Selection with its isCurrentlySelected property set to true.
public Menu(int xPos, int yPos, int wdth, int hght, int lists = 0, int items = 0, bool allSelectable = true)
{
x = xPos;
y = yPos;
width = wdth;
height = hght;
if (items > 0 && lists <= 0)
{
lists = 1;
}
for (int i = 0; i < lists; i++)
{
selections.Add(new List<Selection>());
for (int j = 0; j < items; j++)
{
selections.ElementAt(i).Add(new Selection(((wdth / items) * j) + xPos, ((hght / lists) * i) + yPos, "", 20, allSelectable));
}
}
if (items > 0)
{
selections.ElementAt(0).ElementAt(0).isCurrentlySelected = true;
}
}
Now, within the Menu class, I'm trying to make a method which will deselect the currently selected index, and then select the next closest eligible index in a particular direction, wrapping around to the other side if the end of the range of indices is reached. Unfortunately, all I've been able to come up with is this mess, which currently only works going North, and would need to be expanded to roughly 4x its size to accommodate all directions.
public void nav(Point currentSelected, int dir) // The 4 cardinal directions are represented by an int: 0 for North and continuing clockwise from there.
{
int newRow = currentSelected.Y;
int newIndex = currentSelected.X;
switch (dir)
{
case 0: // Operations to select next eligible N index.
if (this.selections.Count <= 1)
{
return;
}
else
{
int firstOpenRow = this.selections.Count;
for (int i = 0; i < this.selections.Count; i++)
{
int difference = i - currentSelected.Y;
if (difference > 0 && difference < firstOpenRow && this.selections.ElementAt(i).ElementAt(currentSelected.X).isSelectable == true)
{
firstOpenRow = i;
}
}
if (firstOpenRow == this.selections.Count)
{
for (int i = 0; i < this.selections.Count; i++)
{
int difference = i - currentSelected.Y;
if (difference < 0 && difference < firstOpenRow && this.selections.ElementAt(i).ElementAt(currentSelected.X).isSelectable == true)
{
firstOpenRow = i;
}
}
if (firstOpenRow == this.selections.Count)
{
firstOpenRow = currentSelected.Y;
}
}
this.selections.ElementAt(currentSelected.Y).ElementAt(currentSelected.X).isCurrentlySelected = false;
this.selections.ElementAt(firstOpenRow).ElementAt(currentSelected.X).isCurrentlySelected = true;
}
break;
case 1:
// Add operations for E here
break;
case 2:
// Add operations for S here
break;
case 3:
// Add operations for W here
break;
}
}
Your choice of data-structure isn't really well made for the kind of queries you need to make. Maybe you should consider investing a little more time into creating a linked grid. Something like:
class Item
{
Item North { get; private set; }
Item South { get; private set; }
Item West { get; private set; }
Item East { get; private set; }
}
Like that, if you look for the next 'left' item, you can just go West until you either reach null or you encounter an item that is selectable.
Otherwise, it makes sense to distinguish between the different kinds of directions. Just because you have less code doesn't mean your program runs faster. Think of your algorithm in terms of how many operations you have to make to reach your goal, instead of how long it is.
Sorry if that's not the answer your're looking for.

c# Plugin (reflection)

I'm having trouble with creating a plugin solution with reflection. When I click on a menuItem I would like to load and show another program in my window. I figured I would need 3 projects.
Client program that wants to load another program when clicked on menuItem
Program that I want to load
Plugin class
Code client program
private void nQueensToolStripMenuItem_Click(object sender, EventArgs e)
{
// Create an assembly object to load our classes
string path = Application.StartupPath + "\\NQueens.dll";
Assembly ass = Assembly.LoadFile(path);
Type objType = ass.GetType("NQueens.NQueen");
// Create an instace of NQueens.NQueen
var instance = Activator.CreateInstance(objType);
// public static bool berekenQueens()
objType.InvokeMember("berekenQueens",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Static,
null, instance, null);
// private static bool bordValidatie
objType.InvokeMember("bordValidatie",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Static,
null, instance, null);
}
Class
[AttributeUsage(AttributeTargets.Class)]
public class myPluginAttribute : Attribute
{
private bool _bIsPlugin;
public Boolean IsPlugin
{
get { return _bIsPlugin; }
set { _bIsPlugin = value; }
}
private string _sDescription;
public string Description
{
get { return _sDescription; }
set { _sDescription = value; }
}
public myPluginAttribute(Boolean b, String desc)
{
IsPlugin = b;
Description = desc;
}
}
NQueens (program i want to load when clicked on menuitem)
NQueens.cs
public class NQueen
{
public static bool berekenQueens(int Row, int N, bool[,] bord)
{
if (Row >= N) return true;
for (int Col = 0; Col < N; Col++)
{
//Q toevoegen
bord[Row, Col] = true;
//Q + Q volgende Row controleren
if (bordValidatie(Row, Col, bord, N) && berekenQueens(Row + 1, N, bord))
{
return true;
}
//Q verwijderen indien niet door controle
bord[Row, Col] = false;
}
return false;
}
private static bool bordValidatie(int currentRow, int currentCol, bool[,] currentBord, int N)
{
int colstep = 1;
for (int i = currentRow - 1; i >= 0; i--)
{
//rechte lijn
if (currentBord[i, currentCol])
return false;
//linker diagonaal
if (currentCol - colstep >= 0)
{
if (currentBord[i, currentCol - colstep])
return false;
}
//rechter diagonaal
if (currentCol + colstep < N)
{
if (currentBord[i, currentCol + colstep])
return false;
}
colstep += 1;
}
return true;
}
}
MainWindow (nqueens)
public partial class MainWindow : Window
{
public int iN { get { return Convert.ToInt32(txtN.Text); } set { txtN.Text = "" + value; } }
private bool[,] spelbord;
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
spelbord = new bool[iN, iN];
NQueen.berekenQueens(0, iN, spelbord);
visualise(iN, spelbord);
}
private void visualise(int N, bool[,] bord)
{
gridTekenen();
for (int row = 0; row < N; row++)
{
for (int col = 0; col < N; col++)
{
Rectangle rect = new Rectangle();
rect.Stretch = Stretch.Fill;
TextBlock txtB = new TextBlock();
if (spelbord[row, col])
{
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Colors.LightGreen;
rect.Fill = mySolidColorBrush;
txtB.Text = "Q";
}
rect.SetValue(Grid.ColumnProperty, col);
rect.SetValue(Grid.RowProperty, row);
txtB.SetValue(Grid.ColumnProperty, col);
txtB.SetValue(Grid.RowProperty, row);
gridPaneel.Children.Add(rect);
gridPaneel.Children.Add(txtB);
}
}
}
private void gridTekenen()
{
gridPaneel.ShowGridLines = true;
int grooteGrid = int.Parse(txtN.Text);
RowDefinition rowDef;
ColumnDefinition colDef;
for (int i = 0; i < grooteGrid; i++)
{
rowDef = new RowDefinition();
GridLengthConverter myGridLengthConverter = new GridLengthConverter();
GridLength gl1 = (GridLength)myGridLengthConverter.ConvertFromString(150 + "*");
rowDef.Height = gl1;
colDef = new ColumnDefinition();
colDef.Width = gl1;
gridPaneel.RowDefinitions.Add(rowDef);
gridPaneel.ColumnDefinitions.Add(colDef);
}
}
}
I'm stuck trying to get this thing working. How can I make my program to show the NQueens program? How does my client program know the methods from NQueen and use them?
EDIT: I made some changes in the nQueensToolStripMenuItem_Click method. Is this correct now? How can I show the NQueens method in my window now?
As far as I know, you will need a common Interface, which helps communicating with the "Extensions". You will then have three projects:
Your Core Application
A Library just containing the Interface (i.e. IPlugin)
Your Extensions.
Have a look at codeproject to get a better idea about the architecture of plugins.
A much simpler pattern is the classic "Factory Pattern" with interfaces. I've done this before to create plug-ins and it's really straightforward:
1) Create an interface containing all the properties and methods you would ever use to "talk" to the plug-in. Define this in a base class/assembly that will (hardly) ever change.
2) Create a frame UI application which perhaps has one stock implementation of the plug-in interface, perhaps the default menus, so you can easily debug and get your interface right.
3) Now to the dynamic loading... Create a configuration string listing a number of files which should be loaded. Good to allow this to be configurable rather than hard-coding paths, also for security never just load assemblies in a path, you don't know who could have put them there via a back door in file permissions.
4) On start-up use the assembly load from methods to go through each file and once loaded use reflection to query the interfaces, looking for your plugin interface. Store a collection of loaded interfaces/plug-ins and use them as you wish.
Obviously as you have a UI you will have a method to create the child menu items and windows and set their parent to your frame applications menu or client area appropriately. Then you will have some events defined on the interface to deal with events like items being clicked. Makes sense to also define a standard "tool" or command interface, so you can deal with menu items and toolbar items the same way.

How do I swap 2 elements in a list [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Swap two items in List<T>
Edit: Maybe this will work for getting the 'b' value?
for (int i = 0; i < inventory.Count; i++)
{
if (inventory[a].ItemRectangle.Intersects(inventory[i].ItemRectangle))
{
itemB = inventory[i];
}
}
Edit: Here's my progress.
Item itemA;
Item itemB;
int a = -1;
int b = -1;
if (a != -1 && b != -1)
{
itemA = inventory[a];
itemB = inventory[b];
Swap(ref itemA, ref itemB);
inventory[a] = itemA;
inventory[b] = itemB;
}
And here's is where I'm getting the 'a' value.
if (item.ItemSelected == true)
{
a = item.ItemIndex;
}
else
a = -1;
I haven't figured out how to get the 'b' value because I would have to check for an item colliding with another item that are both in the same list. If anybody know how I can do this, please tell me. It would look something like this I guess:
if (item.ItemRectangle.Intersects(//the other item.ItemRectangle)
{
b = item.ItemIndex;
}
else
b = -1;
I've made a List < Item > called inventory. So now I want to implement a swap function, like this:
foreach (Item item in inventory)
{
if (mouseRectangle.Intersects(item.ItemRectangle))
{
if (Input.EdgeDetectLeftMouseDown())
{
switch (item.ItemSelected)
{
case false:
item.ItemSelected = true;
break;
case true:
item.ItemSelected = false;
break;
}
}
}
else if (Input.EdgeDetectLeftMouseDown())
{
switch (item.ItemSelected)
{
case true:
item.ItemSelected = false;
break;
}
}
else if (item.ItemSelected == true)
{
item.ItemPosition = new Vector2(mouseRectangle.X, mouseRectangle.Y);
item.ItemRectangle = new Rectangle(mouseRectangle.X, mouseRectangle.Y, 32, 32);
}
else if (item.ItemSelected == false && //a lot of checks to determine it is not intersecting with an equip slot
{
item.ItemPosition = item.OriginItemPosition;
item.ItemRectangle = item.OriginItemRectangle;
}
else if (item.ItemRectangle.Intersects(item.ItemRectangle))
{
//SwapItem(inventory, item, item);
}
So that's the part of the code I need help with. I want any item in the list to be able to swap with any other item in the list. My SwapItem method is just a placeholder, I dont actually have a SwapItem method yet.
I want the arguments that you pass in to the method to be related to the items I want to swap. So the first item would be the item that I have selected with my mouse, and the other item should be the item that the first item is intersecting with.
To swap an element of the list you can write an extension method as.
public static class ExtensionMethods
{
public static void Swap<T>(this List<T> list, int index1, int index2)
{
T temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
}
}
Remember to put the extension method inside a static class.
then you can do:
yourList.Swap(0,1); // swap element at index 0 with element at index 1
To swap the values of two variables, the easiest method is using references. This is a classic pointer exercise in c++, but it can apply to C# as well.
// Replace int with any data type / class you need
void Swap (ref int a, ref int b)
{
int c = a;
a = b;
b = c;
}
The algorithm used is very simple, and the explanation is usually done like this: you have two glasses, one with water, and one with oil. To put the oil in the first glass, you will need to use a third glass, put the water inside, then put the oil in the first glass, and the water in the second one.
Here is what I had in mind. Look for the comments, so you can understand what's going on.:
// Unlike foreach, with for I can change the values in the list
for (int i = 0; i < inventory.Count; i++)
{
if (mouseRectangle.Intersects(inventory[i].ItemRectangle))
{
if (Input.EdgeDetectLeftMouseDown())
{
// You can replace the switch with this shorter structure
// if A is a bool value, !A will have the opposite value
inventory[i].ItemSelected = !inventory[i].ItemSelected;
}
}
else if (Input.EdgeDetectLeftMouseDown())
{
// You don't need a case-switch for a single condition. An if should suffice
if (inventory[i].ItemSelected)
inventory[i].ItemSelected = false;
}
else if (inventory[i].ItemSelected == true)
{
inventory[i].ItemPosition = new Vector2(mouseRectangle.X, mouseRectangle.Y);
inventory[i].ItemRectangle = new Rectangle(mouseRectangle.X, mouseRectangle.Y, 32, 32);
}
else if (inventory[i].ItemSelected == false && //a lot of checks to determine it is not intersecting with an equip slot
{
inventory[i].ItemPosition = inventory[i].OriginItemPosition;
inventory[i].ItemRectangle = inventory[i].OriginItemRectangle;
}
// Something definitely wrong with this line, a rectangle to instersect with itself??
else if (inventory[i].ItemRectangle.Intersects(inventory[PROBABLY_SOMETHING_ELSE].ItemRectangle))
{
Swap (ref inventory[i], ref inventory[PROBABLY_SOMETHING_ELSE])
}
}

Categories

Resources