C# 旋转及;印刷方格
我有一个关于c#,wpf作业的简短问题。任务是读入一个XML文件,其中包含根面板的一个描述,然后它遵循一个固定模式,其中每个面板都有若干子面板,每个子面板都可以有若干子模式。很明显。我可以很好地阅读它,遍历模型也没有问题 问题是:我必须在wpf画布上打印这些面板。父面板和子面板之间的关系如下所示:C# 旋转及;印刷方格,c#,wpf,algorithm,canvas,mvvm,C#,Wpf,Algorithm,Canvas,Mvvm,我有一个关于c#,wpf作业的简短问题。任务是读入一个XML文件,其中包含根面板的一个描述,然后它遵循一个固定模式,其中每个面板都有若干子面板,每个子面板都可以有若干子模式。很明显。我可以很好地阅读它,遍历模型也没有问题 问题是:我必须在wpf画布上打印这些面板。父面板和子面板之间的关系如下所示: 根面板具有X Y坐标以确定其起点。其他小组则没有 每个面板(包括根部)都有宽度和高度(不一定相同) 每个面板(根面板除外)都有一个属性“attachedToSide”,其值介于0到3之间。该值表示应
- 根面板具有X Y坐标以确定其起点。其他小组则没有
- 每个面板(包括根部)都有宽度和高度(不一定相同)
- 每个面板(根面板除外)都有一个属性“attachedToSide”,其值介于0到3之间。该值表示应将子对象放置在父对象的一侧
- 在针对父面板打印面板时,我们应始终将面板的“0”侧与父面板侧相对
细节:做这一切也纯粹是为了mvvm(只是为了见鬼),所以代码背后有0个代码。这些形状是一个带有自定义itemspaneltemplate和itemtemplate的itemcollection,我通过将旋转角度绑定到模型中的属性来进行旋转。每个面板的模型包括 X,Y coordinates W,H dimensions R rotation value (one of four choices) C a list of up to four children A attached to side 计算子对象的Y值 请注意,子对象的位置主要取决于子对象的旋转值。如果childR为0,则子项位于父项之上。如果childR为1,则该孩子向右,以此类推 因此,如果childR是奇数,则子项与父项具有相同的Y值。如果childR为0,则childY是由孩子的身高调整的父系。当childR为2时,childY是由父项宽度(parentR奇数)或父项高度(parentR偶数)调整的父项 这将导致一个if-else链,如下所示:
if ( childR % 2 ) // odd values, child left or right
childY = parentY
else if ( childR == 0 ) // child above
childY = parentY - childH
else if ( parentR % 2 ) // odd values, adjust by parent width
childY = parentY + parentW
else // even values, adjust by parent height
childY = parentY + parentH
(我在这里假设X,Y坐标表示面板左上角的位置,正Y是向下的。)
X计算与Y计算类似 从根开始,计算根的子元素的X,Y,R,然后递归地计算每个子元素的子元素的参数
这就完成了您的模型。在视图上显示面板非常简单,因为每个面板都有X、Y、W、H、R。您可以使用递归函数打印面板的所有子级,并将所述面板作为参数传递,以便轻松访问位置、变换等。。。类似于:
public void PrintSelfAndChildren(Panel parent)
{
ApplyTransform();
PrintPanel();
foreach(var child in parent.children)
{
PrintSelfAndChildren(child);
}
}
user3386109的回答把我推向了正确的方向,但我得到了一些关于这个问题的额外信息,帮助我解决了这个问题。看看这个例子: 父级打印时0面朝下(这是标准)。它有3个子项:右、上、左。现在,父面板是唯一接收X,Y坐标的面板。(X,Y)是0边的中心。此外,我还得到了宽度和高度。对于以后的所有孩子,我会得到他们的宽度、高度和父母的侧面。因为孩子应该总是用自己的0边连接到父母,所以我可以很容易地使用mod wrapping formule user3386109计算孩子的底面,已经显示了: 底端子节点=(底端父节点+6-父节点附件端)%4 这是最简单的部分。现在,一个复杂的情况是每个孩子都可能比父母宽或小,比父母高或低。这可能会使计算需要绘制的左上角(X,Y)点的问题变得复杂。然而,我一直知道的一件事是,孩子所依附的父侧的中心点应该与接触该父侧的子侧中心点相同(请参见图片上的红线,这将告诉您我的意思) 现在,我使用了以下方法:我决定计算左上角点的坐标,假设我可以“竖直”绘制子对象,因此底部是0边。然后,我会沿着那个点旋转 举个例子: 请注意黑色的父面板。我从XML中知道,我需要将子面板附加到父面板的第1面。因此,我从父1侧的0侧中心计算其中心点。我知道这将是孩子们0边的中心,因为那是我需要将他们连接在一起的地方。然后我计算childs的左上(X,Y)坐标,这很简单。之后,我可以沿着子对象的中心0边点旋转子对象。然后我们得到以下结果,其中父对象和子对象在中心连接,子对象也以正确的方式旋转 简言之,始终采用相同的方法:
- 取父对象0边的中心(我们将存储在每个面板对象中)
- 相对于该点,计算子对象0侧中心的位置
- 如果我们有那一点,计算孩子们的身高
public void PrintSelfAndChildren(Panel parent) { ApplyTransform(); PrintPanel(); foreach(var child in parent.children) { PrintSelfAndChildren(child); } }
private static Rectangle CreateRectangle(string name, float width, float height, int sideOfParent, float offset, Rectangle parent) { Rectangle rect = new Rectangle() { Name = name, Width = width, Height = height, Offset = offset }; // Calculate which side should be at the bottom, depending on the bottom side of the parent, // and which side of the parent the new rectangle should be attached to rect.BottomSide = (parent.BottomSide + 6 - sideOfParent) % 4; // Calculate the bottom mid point of the rectangle // If | bottom side parent - bottom side child | = 2, just take over the mid bottom point of the parent if (Math.Abs(parent.BottomSide - rect.BottomSide) == 2) { rect.MidBottom = parent.MidBottom; } else { // Alternative cases // Formulas for both bottom side parent = 0 or 2 are very similar per bottom side child variation (only plus/minus changes for Y formulas) // Formulas for both bottom side parent = 1 or 3 are vary similar per bottom side child variation (only plus/minus changes for X formulas) // Therefor, we create a "mutator" 1 / -1 if needed, to multiply one part of the formula with, so that we either add or subtract Point parPoint = parent.MidBottom; if (parent.BottomSide % 2 == 0) { // Parent has 0 or 2 at the bottom int mutator = (parent.BottomSide == 0) ? 1 : -1; switch (rect.BottomSide % 2 == 0) { case true: rect.MidBottom = new Point(parPoint.X, parPoint.Y - (mutator * parent.Height)); break; case false: if (rect.BottomSide == 1) rect.MidBottom = new Point(parPoint.X + (parent.Width / 2), parPoint.Y - (mutator * (parent.Height / 2))); else rect.MidBottom = new Point(parPoint.X - (parent.Width / 2), parPoint.Y - (mutator * (parent.Height / 2))); break; } } else { // Parent has 1 or 3 at the bottom int mutator = (parent.BottomSide == 1) ? 1 : -1; switch (rect.BottomSide % 2 == 1) { case true: rect.MidBottom = new Point(parPoint.X + (mutator * parent.Height), parPoint.Y); break; case false: if (rect.BottomSide == 0) rect.MidBottom = new Point(parPoint.X + (mutator * (parent.Height / 2)), parPoint.Y - (parent.Width / 2)); else rect.MidBottom = new Point(parPoint.X + (mutator * (parent.Height / 2)), parPoint.Y + (parent.Width / 2)); break; } } } return rect; }