爲了使畫布自動調整其大小以便我的ScrollViewer正常工作,我創建了一個從Canvas派生的類,然後覆蓋MeasureOverride方法以使畫布根據UIElements出現在畫布上。在MVVM應用程序中使用滾動查看器的畫布
public class DesignerCanvas : Canvas
{
protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
foreach (UIElement element in Children)
{
double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left = double.IsNaN(left) ? 0 : left;
top = double.IsNaN(top) ? 0 : top;
element.Measure(constraint);
Size desiredSize = element.DesiredSize;
if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
{
size.Width = Math.Max(size.Width, left + desiredSize.Width);
size.Height = Math.Max(size.Height, top + desiredSize.Height);
}
}
// add some extra margin
size.Width += 10;
size.Height += 10;
base.InvalidateMeasure();
return size;
}
}
XAML:
<ScrollViewer HorizontalScrollBarVisibility="Visible">
<local:DesignerCanvas x:Name="designerCanvas" AllowDrop="True">
<ItemsControl Name="Shapes">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</local:DesignerCanvas>
</ScrollViewer>
而且ScrollViewer中正常工作,每當我添加/直接刪除圖形到DesignerCanvas!除非我不是。我走了MVVM的做法,所以我數據綁定我的畫布到的ObservableCollection
private ObservableCollection<Shape> shapes = new ObservableCollection<Shape>();
public ObservableCollection<Shape> Shapes
{
get { return shapes; }
set { shapes = value; }
}
形狀顯示每當項目添加到的ObservableCollection在畫布上。但是,畫布不能正確調整自身的大小,導致我的scrollviewer無法正常工作。這是預期的,因爲我不直接操作DesignerCanvas,所以不會調用MeasureOverride。
我可以在DesignerCanvas上調用InvalidateMeasure,但這需要我的viewmodel有關於視圖的知識。如何在不中斷MVVM的情況下解決這個問題?
編輯:我也想聽聽任何建議,如果它真的值得讓這種問題保持這樣的問題。最近,我覺得MVVM給我的問題比解決方案更多。
編輯2:哦..好的,這個問題比我想象的要複雜得多。從Florian Gl的建議,我繼續並在我的viewmodel中創建了一個事件,然後在我的視圖中處理該事件以調用designerCanvas.InvalidateMeasure()。
這會在DesignerCanvas中調用我的MeasureOverride方法。除非它不正確地調整我的畫布大小,所以scrollviewer仍然無法正常工作。我注意到,我沒有直接向DesignerCanvas的子元素添加圖形,而是直接添加到數據綁定到Canvas的observablecollection。因此,在我的foreach語句中沒有UIElement循環通過
protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
ItemsControl itemsControl = Children.OfType<ItemsControl>().First();
foreach (UIElement element in Children) //No UIElements inside Children
{
double left = Canvas.GetLeft(element);
...
現在我真的被卡住了。我怎樣才能繞過這個問題?
爲什麼不在你的xaml.cs中調用designerCanvas.InvalidateMeasure()?這會打破MVVM嗎? –
@FlorianGl絕對不是,但問題是如何知道何時調用該方法?在我看來,我並不瞭解ViewModel中的observablecollection,所以我無法分辨何時項目正在從集合中添加/刪除。我能想到的唯一可行的選擇是附加定期計時器或其他東西,並調用invalidate方法,但這是一個非常骯髒的解決方案。 – l46kok
您可以在ViewModel中添加一個事件(例如MyCollectionChanged),並在集合發生變化時觸發它。在事件觸發時,您可以在您的xaml.cs中調用designerCanvas.InvalidateMeasure()。 –