C# 类似绘画的Windows应用程序的设计注意事项

C# 类似绘画的Windows应用程序的设计注意事项,c#,C#,我正在为用C编写的旧的开源流体建模引擎开发一个新的前端。我正在使用C#和WPF。“应用程序网络生成”要求用户绘制管道、蓄水池、节点、储罐等的网络。该应用程序或多或少是一个花哨的paint版本;) 现在,我有如下设置的图形。我有一个嵌入式win forms面板,其中包含mouseclick、mousemove和paint事件。鼠标单击将单击的坐标保存到singleton类中的数组中,然后通过invalidate()触发绘制事件。然后,绘制事件在数组中循环,并通过以下方式绘制数组中的所有节点坐标:g

我正在为用C编写的旧的开源流体建模引擎开发一个新的前端。我正在使用C#和WPF。“应用程序网络生成”要求用户绘制管道、蓄水池、节点、储罐等的网络。该应用程序或多或少是一个花哨的paint版本;)

现在,我有如下设置的图形。我有一个嵌入式win forms面板,其中包含mouseclick、mousemove和paint事件。鼠标单击将单击的坐标保存到singleton类中的数组中,然后通过
invalidate()触发绘制事件。然后,绘制事件在数组中循环,并通过以下方式绘制数组中的所有节点坐标:
g.FillEllipse(x,y,20,20)
用户可以单击一个节点,通过我编写的名为
DoesPointExist(xCord,yCord)的函数打开菜单。它在坐标数组中循环,如果xcord和ycord都在单击坐标的5px范围内,则返回true。这是一个有点过时的解决方案,但似乎效果很好

到目前为止,这对我来说非常有效。但在未来,我将不得不给每个节点(或面板上的圆)越来越多的属性。没什么特别的,只是一些数值,比如必须与每个节点关联的高程。此外,我还需要添加一个选项,以便在某个点删除节点

我可以通过将已删除行的所有值设置为0,并将if语句置于paintevents循环中,以不绘制已删除的点,或者甚至找出如何摆脱行周期并将所有其他值向下移动来实现这一点

我的问题是,有没有一种更智能、更面向对象的方法来实现这一点?循环和数组似乎有点过时,必须有更好的方法来利用C#特性。我是否可以设置某种对象或类来简化此过程?数组很好,但到最后它将是40-50列。我的背景更多的是使用诸如C之类的低级语言进行函数型编程。我的程序似乎没有对象和类,而不是全局数据的单例玻璃杯

我知道有不同的方法给猫剥皮;但重要的是,我编写的代码对于未来的工程师来说是可访问和易于修改的,因此我希望在OOP范例中添加尽可能多的内容。我目前的代码非常实用。。。但不是很整洁

绘制事件代码:

private void wfSurface_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
        Graphics g;
        Graphics h;
        g = wfSurface.CreateGraphics();
        h = wfSurface.CreateGraphics();
        epanet epa = epanet.GetInstance();
        SolidBrush black = new SolidBrush(System.Drawing.Color.Black);
        SolidBrush blue = new SolidBrush(System.Drawing.Color.Pink);
        SolidBrush green = new SolidBrush(System.Drawing.Color.Green);
        System.Drawing.Pen line = new System.Drawing.Pen(System.Drawing.Color.FromArgb(255, 0, 0, 0));

        //Loop to draw vertical grid lines
        for (int f = 50; f < 1100; f += 50)
        {
            e.Graphics.DrawLine(line, f, 0, f, 750);
        }

        //Loop to draw vertical grid lines
        for (int d = 50; d < 750; d += 50)
        {
            e.Graphics.DrawLine(line, 0, d, 1100, d);
        }

        //Loop nodes, tanks, and resevoirs
        for (int L = 1; L < index; L += 1)
        {
            g.FillEllipse(black, Convert.ToInt32(epa.newNodeArray[L, 0] - 8), Convert.ToInt32(epa.newNodeArray[L, 1] - 8), 19, 19);
            h.FillEllipse(blue, Convert.ToInt32(epa.newNodeArray[L, 0] - 6), Convert.ToInt32(epa.newNodeArray[L, 1] - 6), 15, 15);
        }

        for (int b = 1; b < resIndex; b += 1)
        {
            g.FillRectangle(green, Convert.ToInt32(epa.ResArray[b, 0] - 8), Convert.ToInt32(epa.ResArray[b, 1] - 8), 16, 16);
        }
        for (int c = 1; c < tankIndex; c += 1)
        {
            g.FillRectangle(black, Convert.ToInt32(epa.tankArray[c, 0] - 8), Convert.ToInt32(epa.tankArray[c, 1] - 8), 20, 20);
            g.FillRectangle(green, Convert.ToInt32(epa.tankArray[c, 0] - 6), Convert.ToInt32(epa.tankArray[c, 1] - 6), 16, 16);
        }
}
singleton类的代码:

public class epanet 
{ 私有静态epanet实例=新epanet()

private epanet(){}
公共静态epanet GetInstance()
{
返回实例;
}
//Microsoft.Win32.SaveFileDialog save=新建Microsoft.Win32.SaveFileDialog();
//网络节点数据
公共int节点索引{get;set;}
public int newNodeIndex{get;set;}
公共双xCord{get;set;}
公共双字节码{get;set;}
公共双端口{get;set;}
公共双端口{get;set;}
public int selectedPoint{get;set;}
//public List nodeList=新列表();
//保存数据
public int fileCopyNum{get;set;}
公共字符串文件名{get;set;}
公共字符串路径{get;set;}
公共字符串fullFileName{get;set;}
//窗口条件数据
公共bool状态{get;set;}
公共bool windowOpen{get;set;}
公共bool OpenClicked{get;set;}
公共布尔存储{get;set;}
public bool newClicked{get;set;}
公共bool propOpen{get;set;}
//图形控件
公共字符串控件已选定{get;set;}
//声明数组以存储坐标
公开双票[,]noderray=新双票[100000,3];
公共双票[,]newnoderray=新双票[100000,7];
公共双票[,]重票=新双票[100000,7];
公共双精度[,]坦克阵列=新双精度[100000,7];
公共无效新闻记录(int-newNodeIndex、双xCord、双yCord)
{
newNodeArray[newNodeIndex,0]=xCord;
newnoderray[newNodeIndex,1]=yCord;
newNodeArray[nodeIndex,2]=nodeIndex;
}
public void setResCords(int newNodeIndex,双xCord,双yCord)
{
重新排列[newNodeIndex,0]=xCord;
重新排列[newNodeIndex,1]=yCord;
重新排列[节点索引,2]=节点索引;
}
公共无效设置存储电缆(int newNodeIndex、双xCord、双yCord)
{
tankArray[newNodeIndex,0]=xCord;
tankArray[newNodeIndex,1]=yCord;
tankArray[nodeIndex,2]=nodeIndex;
}
公共无效设置记录(int节点索引、双xCord、双yCord)
{
noderray[nodeIndex,0]=xCord;
noderray[nodeIndex,1]=yCord;
//noderray[nodeIndex,2]=nodeIndex;
}
公共布尔值不存在(双xcord、双ycord、整数索引)
{
整数计数=1;
布尔结果=假;
while(计数<索引)
{            
if(Math.Abs(xcord-newnoderray[count,0])<20)
{
if(Math.Abs(ycord-newnoderray[count,1])<20)
{                    
结果=正确;
selectedPoint=计数;
指数=0;
}
}
计数+=1;
}
返回结果;
}

正如我所说的,一切都很好。我只是想了解一下是否有更专业的方法来完成这项工作。

如果你用C做过很多编程,你应该熟悉链表的概念。链表比数组有用得多,因为它可以让你从constan列表中的任何一点删除在C#中,您需要查看
System.Collections.Generic.List
以利用它

除此之外,标准的面向对象设计是查看您的功能需求并查找名词,这些名词应该成为您的类因此,与其拥有一个顶点数组,不如拥有一个节点的链接列表。每个节点都可以具有坐标和高程等属性,如果需要更多属性,则可以进行扩展。注意,如果发现节点类越来越麻烦,这就是
public class epanet 
private epanet() { }

public static epanet GetInstance()
{
    return instance;
}

//Microsoft.Win32.SaveFileDialog save = new Microsoft.Win32.SaveFileDialog();

//Network Node Data
public int nodeIndex { get; set; }
public int newNodeIndex { get; set; }
public double xCord { get; set; }
public double yCord { get; set; }
public double x1Cord { get; set; }
public double y1Cord { get; set; }
public int selectedPoint { get; set; }
//public List<double> nodeList = new List<double>();

//Saving Data
public int fileCopyNum { get; set; }
public string filename { get; set; }
public string path { get; set; }
public string fullFileName { get; set; }

//Window Condition Data
public bool drawSurfStatus { get; set; }
public bool windowOpen { get; set; }
public bool OpenClicked { get; set; }
public bool saveASed { get; set; }
public bool newClicked { get; set; }
public bool propOpen { get; set; }

//Drawing Controls
public string controlSelected { get; set; }

//Declare Array to store coordinates
public double[,] nodeArray = new double[100000, 3];
public double[,] newNodeArray = new double[100000, 7];
public double[,] ResArray = new double[100000, 7];
public double[,] tankArray = new double[100000, 7];

public void newSetCords(int newNodeIndex, double xCord, double yCord)
{
    newNodeArray[newNodeIndex, 0] = xCord;
    newNodeArray[newNodeIndex, 1] = yCord;
    newNodeArray[nodeIndex, 2] = nodeIndex;

}

public void setResCords(int newNodeIndex, double xCord, double yCord)
{
    ResArray[newNodeIndex, 0] = xCord;
    ResArray[newNodeIndex, 1] = yCord;
    ResArray[nodeIndex, 2] = nodeIndex;

}

public void setTankCords(int newNodeIndex, double xCord, double yCord)
{
    tankArray[newNodeIndex, 0] = xCord;
    tankArray[newNodeIndex, 1] = yCord;
    tankArray[nodeIndex, 2] = nodeIndex;

}

public void setCords(int nodeIndex, double xCord, double yCord)
{
    nodeArray[nodeIndex, 0] = xCord;
    nodeArray[nodeIndex, 1] = yCord;
    //nodeArray[nodeIndex, 2] = nodeIndex;

}

public bool DoesPointExist(double xcord, double ycord, int index)
{
    int count = 1;
    bool outcome = false;        
    while (count < index)
    {            
        if (Math.Abs(xcord - newNodeArray[count, 0]) < 20)
        {
            if (Math.Abs(ycord - newNodeArray[count, 1]) < 20 )
            {                    
                outcome = true;
                selectedPoint = count;
                index = 0;                    
            }
        }
        count += 1;
    }

    return outcome;        
}