2012-09-25 72 views
0

爲了使畫布自動調整其大小以便我的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); 
      ... 

現在我真的被卡住了。我怎樣才能繞過這個問題?

+0

爲什麼不在你的xaml.cs中調用designerCanvas.InvalidateMeasure()?這會打破MVVM嗎? –

+0

@FlorianGl絕對不是,但問題是如何知道何時調用該方法?在我看來,我並不瞭解ViewModel中的observablecollection,所以我無法分辨何時項目正在從集合中添加/刪除。我能想到的唯一可行的選擇是附加定期計時器或其他東西,並調用invalidate方法,但這是一個非常骯髒的解決方案。 – l46kok

+0

您可以在ViewModel中添加一個事件(例如MyCollectionChanged),並在集合發生變化時觸發它。在事件觸發時,您可以在您的xaml.cs中調用designerCanvas.InvalidateMeasure()。 –

回答

1

我的事件流的Idea:

  1. 創建視圖模型自己的事件:在視圖模型

    public delegate void MyCollectionChangedEventArgs(); 
    public event MyCollectionChangedEventArgs MyCollectionChanged; 
    
  2. 贖回事件:

    if (MyCollectionChanged != null) 
    { 
        MyCollectionChanged(); 
    } 
    
  3. 讓您查看了解事件:

    MainWindowViewModel vm = new MainWindowViewModel(); 
        vm.MyCollectionChanged += new MainWindowViewModel.MyCollectionChangedEventArgs(MainWindowViewModel_MyCollectionChanged); 
    

    MainWindowViewModel vm = (MainWindowViewModel)DataContext; 
        vm.MyCollectionChanged += new MainWindowViewModel.MyCollectionChangedEventArgs(MainWindowViewModel_MyCollectionChanged); 
    
  4. 電話方法:

    void MainWindowViewModel_MyCollectionChanged() 
    { 
        designerCanvas.InvalidateMeasure() 
    } 
    

編輯: 我不知道如果我提出以下建議在的MeasureOverride法的工作,但你可以嘗試:

(MainWindowViewModel) mvm = (MainWindowViewModel)DataContext; 

    foreach (UIElement element in mvm.Shapes) 
    { ... } 
+0

GI感謝您的回答,並且這是在不中斷MVVM的情況下調用invalidatemeasure方法的好方法。但是,我發現我的問題比這個更復雜。請參閱我的編輯。 – l46kok

+0

現在看我的編輯;) –

+0

GI大聲笑,這是非常簡單的。我想我必須習慣在盒子外面思考。非常感謝 – l46kok

相關問題