vendredi 27 mars 2015

What is the proper design for interacting with controls using MVVM where I need to do calculations based on XAML controls?

I am still a bit green in WPF. I am refactoring a sizable applications where all the work was done in the code behind. I am refactoring to use MVVM.


A bit about the application: This application contains a single window, the single window and the pertinent pieces of the XAML are below:



<Grid>
<Border Style="{StaticResource ClipBorderStyle}" Name="ImageBorder">
<Grid Style="{StaticResource ClipGridStyle}" Name="ImageGrid">
<Image Name="KeyImage" Style="{StaticResource MainImageStyle}" Source="{Binding ImageSource}" Cursor="{Binding ImageCursor}"></Image>
<Canvas Name="KeyCanvas" Height="{Binding Source=KeyImage, Path=Height}" common:CanvasAssistant.BoundChildren="{Binding CanvasControls}"></Canvas>
</Grid>
</Border>
</Grid>


When the user clicks on the image, I drop a control onto the Canvas at the location where the user clicked. There can be many objects, and multiple control types. Currently I have a view model defined for each of the different control types and I keep an observable collection of them in a main view model. I am about half way through refactoring, and am realizing I still have a ton of work being done in the code behind, and am modifying the objects in the DataContext a lot. I am curious how I can move a lot of this out of the code behind into a more structured format (maybe into the view model, maybe another pattern). If it were simply modifying data, this would not be a problem, but in many cases I need to do transforms, and track the location on the image. The user can interact with the application using both their mouse and their keyboard (click to select an object, left arrow to move it, etc).


The Core Questions When I have to to something like any of the following:



private Point TranslateImageCoordinatesToParentGrid(Point pointOnImage)
{
return KeyImage.TransformToVisual(ImageGrid).Transform(pointOnImage);
}


OR



private void Marker_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var Marker = (Marker)sender;
if (Marker.IsMouseCaptured)
Marker.ReleaseMouseCapture();
}


OR



private void Marker_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var Marker = (Marker)sender;
Marker.CaptureMouse();
_dataContext.SelectedObject = Marker;
Marker.Focus();
}


OR



private void controlMarker_OnMouseMove(object sender, MouseEventArgs e)
{
var controlMarker = (controlMarker)sender;
var controlDataContext = ((controlMarkerObject)controlMarker.DataContext);
if (!controlMarker.IsMouseCaptured) return;

var tt =
(TranslateTransform)
((TransformGroup)controlMarker.RenderTransform).Children.First(tr => tr is TranslateTransform);
var currentMousePos = e.GetPosition(ImageGrid);

// center mouse on controlMarker
currentMousePos -= controlDataContext.CenterOffsetFromTopLeft;

var v = _dataContext.Start - currentMousePos;
tt.X = _dataContext.Origin.X - v.X;
tt.Y = _dataContext.Origin.Y - v.Y;


var currentImagePos = TranslateImageGridCoordinatesToChildImage(currentMousePos + controlDataContext.TopLeftOffset);

controlDataContext.ImagePosition = currentImagePos;
}



  1. Where is the appropriate place for this logic that interacts with both the view and the view model (and view models for the controls)?

  2. Is the code behind the appropriate place for this?

  3. Should I be using this eventing model where I defined the mouse events, or convert them to ICommands?

  4. Is there a better/cleaner pattern to use for an application like this?


Aucun commentaire:

Enregistrer un commentaire