2014-01-16 78 views
2

我有一個複雜的繪製渲染控制,我已經放入一個視圖。什麼是處理與MVVM模式相關的縮放的理想方式?我希望用戶能夠通過點擊和拖動陰謀進行縮放。通過MVVM模式縮放圖形?

我看到的一種方法是採用Plot控件的MouseMove,MouseUp,MouseDown事件並將它們連接到PlotViewModel中的命令。現在,響應命令ViewModel可以更新它的ZoomLevel屬性,該屬性可以綁定到視圖,並使視圖放大。當用戶點擊並拖動時,我還想顯示一個矩形,指示將會被放大。將縮放預覽中的AnnotationViewModel保存在PlotViewModel中是否有意義?

另一種方法是在視圖中處理它,而不涉及ViewModel。

我看到的主要區別是捕獲ViewModel中的行爲將使該行爲在View中的可重用性更高。雖然我有一種感覺,底層Plot控件和結果視圖足夠複雜,無論如何不會有太多的重用機會。你怎麼看?

+5

'Zoom'似乎是一個**查看特定的**關注。處理視圖級別的問題。 ViewModel與此無關(除非您想在數據庫中保存縮放級別值或者使用它們執行一些應用程序邏輯) –

回答

0

我認爲有幾種方法可以解決您的問題。 HighCore的權利,當他說Zoom適用於View時,建議將其放在View一側。但是有其他選擇,我們在下面考慮它們。不幸的是,我沒有處理Plot RenderingControl,所以我將描述一個基於抽象的解決方案,與控件無關。

AttachedBehavior

在這種情況下,我會試圖通過一個附加行爲來識別可能的所有與控制的工作,它非常適合於MVVM模式,並且它可以在該共混物中使用。工作

在你View,控制的定義和連接行爲,就像這樣:

<RenderingControl Name="MyPlotControl" 
        AttachedBehaviors:ZoomBehavior.IsStart="True" ... /> 

而在後臺代碼:

public static class ZoomBehavior 
{ 
    public static readonly DependencyProperty IsStartProperty; 

    public static void SetIsStart(DependencyObject DepObject, bool value) 
    { 
     DepObject.SetValue(IsStartProperty, value); 
    } 

    public static bool GetIsStart(DependencyObject DepObject) 
    { 
     return (bool)DepObject.GetValue(IsStartProperty); 
    } 

    static ZoomBehavior() 
    { 
     IsStartMoveProperty = DependencyProperty.RegisterAttached("IsStart", 
                  typeof(bool), 
                  typeof(ZoomBehavior), 
                  new UIPropertyMetadata(false, IsStart)); 
    } 

    private static void IsStart(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     UIElement uiElement = sender as UIElement; 

     if (uiElement != null) 
     { 
      if (e.NewValue is bool && ((bool)e.NewValue) == true) 
      { 
       uiElement.MouseDown += new MouseButtonEventHandler(ObjectMouseDown); 
       uiElement.MouseMove += new MouseEventHandler(ObjectMouseMove); 
       uiElement.MouseUp += new MouseButtonEventHandler(ObjectMouseUp); 
      } 
     } 
    } 

    // Below is event handlers 
} 

一旦你'設置爲true for property IsStart,PropertyChanged處理程序被觸發,併爲包含基本邏輯的事件設置處理程序。

額外的數據在你的行爲傳遞註冊額外的依賴屬性,例如:

<RenderingControl Name="MyPlotControl" 
        AttachedBehaviors:ZoomBehavior.IsStart="True" 
        AttachedBehaviors:ZoomBehavior.ZoomValue="50" /> 

在後臺代碼:

// ... Here registered property 

public static void SetZoomValue(DependencyObject DepObject, int value) 
{ 
    DepObject.SetValue(ZoomValueProperty, value); 
} 

public static int GetZoomValue(DependencyObject DepObject) 
{ 
    return (int)DepObject.GetValue(ZoomValueProperty); 
} 

// ... Somewhere in handler 

int value = GetZoomValue(plotControl); 

要在行爲檢索數據,我用的是單身模式。該模式表示對象的全局靜態訪問點,並且必須保證類的單個實例的存在。

使用這種模式(從行爲取,誰與時間顯示在 View工作)的

實施例:

public class TimeBehavior : INotifyPropertyChanged 
{ 
    // Global instance 
    private static TimeBehavior _instance = new TimeBehavior(); 

    public static TimeBehavior Instance 
    { 
     get 
     { 
      return _instance; 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private string _currentTime = DateTime.Now.ToString("HH:mm"); 

    public string CurrentTime 
    { 
     get 
     { 
      return _currentTime; 
     } 

     set 
     { 
      if (_currentTime != value) 
      { 
       _currentTime = value; 

       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, new PropertyChangedEventArgs("CurrentTime")); 
       } 
      } 
     } 
    } 

    private string _currentDayString = ReturnDayString(); 

    public string CurrentDayString 
    { 
     get 
     { 
      return _currentDayString; 
     } 

     set 
     { 
      if (_currentDayString != value) 
      { 
       _currentDayString = value; 

       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, new PropertyChangedEventArgs("CurrentDayString")); 
       } 
      } 
     } 
    } 

    private string _currentMonthAndDayNumber = ReturnMonthAndDayNumber(); 

    public string CurrentMonthAndDayNumber 
    { 
     get 
     { 
      return _currentMonthAndDayNumber; 
     } 

     set 
     { 
      if (_currentMonthAndDayNumber != value) 
      { 
       _currentMonthAndDayNumber = value; 

       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, new PropertyChangedEventArgs("CurrentMonthAndDayNumber")); 
       } 
      } 
     } 
    } 

    public static readonly DependencyProperty IsTimerStartProperty; 

    public static void SetIsTimerStart(DependencyObject DepObject, bool value) 
    { 
     DepObject.SetValue(IsTimerStartProperty, value); 
    } 

    public static bool GetIsTimerStart(DependencyObject DepObject) 
    { 
     return (bool)DepObject.GetValue(IsTimerStartProperty); 
    } 

    static void OnIsTimerStartPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     if (e.NewValue is bool && ((bool)e.NewValue) == true) 
     { 
      DispatcherTimer timer = new DispatcherTimer(); 
      timer.Interval = TimeSpan.FromMilliseconds(1000); 
      timer.Tick += new EventHandler(timer_Tick); 
      timer.Start(); 
     } 
    } 

    static TimeBehavior() 
    { 
     IsTimerStartProperty = DependencyProperty.RegisterAttached("IsTimerStart", 
                   typeof(bool), 
                   typeof(TimeBehavior), 
                   new PropertyMetadata(new PropertyChangedCallback(OnIsTimerStartPropertyChanged))); 
    } 

    private static void timer_Tick(object sender, EventArgs e) 
    { 
     _instance.CurrentTime = DateTime.Now.ToString("HH:mm"); 
     _instance.CurrentDayString = ReturnDayString(); 
     _instance.CurrentMonthAndDayNumber = ReturnMonthAndDayNumber(); 
    } 
} 

訪問數據在View

<TextBlock Name="WidgetTimeTextBlock" 
      Text="{Binding Path=CurrentTime, 
          Source={x:Static Member=AttachedBehaviors:TimeBehavior.Instance}}" /> 

替代

通過接口工作

這種方式的一點是,我們通過ViewModel調用View中的方法,該方法完成所有工作,並且他不知道View。這是通過界面操作完成,在這裏很好的描述:

Talk to View

使用服務定位

服務定位器可以讓你在工作ViewModel,在不違反MVVM原則。您有一個RegisterService方法,您可以在其中註冊要提供的服務的實例以及您將用於獲取所需服務的GetService方法。

更多信息可以在這裏找到:

Service Locator in MVVM