我試圖寫一個自定義Panel
類WPF,通過覆蓋MeasureOverride
和ArrangeOverride
但是,雖然這是大多工作我遇到了一個奇怪的問題,我無法解釋。自定義自動調整大小WPF Panel類
我特別呼籲後,我的子項Arrange
在ArrangeOverride
搞清楚它們的大小應該是什麼,他們沒有大小的尺寸,我給他們後,和似乎上漿傳遞給他們的大小Measure
方法MeasureOverride
。
我錯過了這個系統應該如何工作?我的理解是,撥打Measure
只會導致孩子根據提供的可用尺寸評估其DesiredSize
,並且不應影響其實際最終尺寸。
這裏是我的完整代碼(面板,順便說一句,旨在以最節省空間的方式安排兒童,給不需要它的行留出更少的空間,並將餘下的空間均勻地分開 - 它目前只支持垂直方向,但我計劃加水平一旦我得到它正常工作):
編輯:感謝您的答覆。我會稍後仔細檢查它們。不過,讓我澄清我的預期算法是如何工作的,因爲我沒有解釋這一點。
首先,想想我正在做的事情的最佳方式是想象每行設置爲*的網格。這將均勻分隔空間。但是,在某些情況下,連續的元素可能不需要所有的空間;如果是這種情況,我想把剩下的空間放到那些可以使用空間的行上。如果沒有行需要任何額外的空間,我只是嘗試平均分配東西(這就是extraSpace
正在做的事情,只是爲了這種情況)。
我這樣做了兩次。第一遍的終點是確定一排的最終「正常尺寸」 - 即,將縮小的行的大小(給定比所需大小更小的大小)。我這樣做是通過將最小項目逐步增加到最大並在每個步驟調整計算的正常大小,方法是將每個小項目的剩餘空間添加到每個後續較大項目,直到沒有更多項目「合適」然後中斷。
在下一回閤中,我使用這個正常值來確定一個物品是否適合,只需將正常尺寸的Min
與物品的所需尺寸對齊即可。
(我也改變了匿名方法爲簡單lambda函數)。
編輯2:我的算法似乎在確定孩子的適當大小的工作很大。但是,孩子們並沒有接受他們的尺寸。我通過傳遞PositiveInfinity並返回Size(0,0)來嘗試Goblin的建議MeasureOverride
,但是這會讓孩子們自己畫出來,好像根本沒有空間限制。對此不明顯的部分是由於致電Measure
而發生。微軟關於這個主題的文檔並不完全清楚,因爲我已經多次閱讀過每個類和屬性描述。但是,現在很明顯,調用Measure
實際上會影響孩子的渲染,因此我將嘗試按照BladeWise建議的方式將這兩個函數中的邏輯分開。
解決!我得到它的工作。正如我所懷疑的,我需要每個孩子兩次調用Measure()(一次評估DesiredSize,第二次給每個孩子適當的身高)。在我看來,WPF中的佈局將被設計成一種奇怪的方式,在這裏它被分成兩個傳球,但測量傳球實際上做了兩件事:措施和大小的孩子和排列傳球旁邊沒有任何東西實際上對孩子進行身體定位非常奇怪。
我會在底部發布工作代碼。
首先,原來的(碎)代碼:
protected override Size MeasureOverride(Size availableSize) {
foreach (UIElement child in Children)
child.Measure(availableSize);
return availableSize;
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize) {
double extraSpace = 0.0;
var sortedChildren = Children.Cast<UIElement>().OrderBy<UIElement, double>(child=>child.DesiredSize.Height;);
double remainingSpace = finalSize.Height;
double normalSpace = 0.0;
int remainingChildren = Children.Count;
foreach (UIElement child in sortedChildren) {
normalSpace = remainingSpace/remainingChildren;
if (child.DesiredSize.Height < normalSpace) // if == there would be no point continuing as there would be no remaining space
remainingSpace -= child.DesiredSize.Height;
else {
remainingSpace = 0;
break;
}
remainingChildren--;
}
// this is only for cases where every child item fits (i.e. the above loop terminates normally):
extraSpace = remainingSpace/Children.Count;
double offset = 0.0;
foreach (UIElement child in Children) {
//child.Measure(new Size(finalSize.Width, normalSpace));
double value = Math.Min(child.DesiredSize.Height, normalSpace) + extraSpace;
child.Arrange(new Rect(0, offset, finalSize.Width, value));
offset += value;
}
return finalSize;
}
而這裏的工作代碼:
double _normalSpace = 0.0;
double _extraSpace = 0.0;
protected override Size MeasureOverride(Size availableSize) {
// first pass to evaluate DesiredSize given available size:
foreach (UIElement child in Children)
child.Measure(availableSize);
// now determine the "normal" size:
var sortedChildren = Children.Cast<UIElement>().OrderBy<UIElement, double>(child => child.DesiredSize.Height);
double remainingSpace = availableSize.Height;
int remainingChildren = Children.Count;
foreach (UIElement child in sortedChildren) {
_normalSpace = remainingSpace/remainingChildren;
if (child.DesiredSize.Height < _normalSpace) // if == there would be no point continuing as there would be no remaining space
remainingSpace -= child.DesiredSize.Height;
else {
remainingSpace = 0;
break;
}
remainingChildren--;
}
// there will be extra space if every child fits and the above loop terminates normally:
_extraSpace = remainingSpace/Children.Count; // divide the remaining space up evenly among all children
// second pass to give each child its proper available size:
foreach (UIElement child in Children)
child.Measure(new Size(availableSize.Width, _normalSpace));
return availableSize;
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize) {
double offset = 0.0;
foreach (UIElement child in Children) {
double value = Math.Min(child.DesiredSize.Height, _normalSpace) + _extraSpace;
child.Arrange(new Rect(0, offset, finalSize.Width, value));
offset += value;
}
return finalSize;
}
它可能不是超高效什麼用不必調用Measure
兩次(和迭代Children
三次),但它的工作原理。任何優化算法將不勝感激。
一兩件事:我不擔心異常從'MeasureOverride'返回'availableSize'因爲面板使內無限毫無意義像ScrollViewer一樣的空間。只有空間狹窄時纔有意義。 – devios1 2010-06-09 15:22:46
我也有這個問題。 ArrangeOverride中的任何尺寸變化只是代替剪輯。不是我期望閱讀文檔或任何WPF書籍。也曾採取兩次措施來解決這個問題。謝謝。 – 2010-09-20 17:50:20