c# - Mouse Position with respect to image in WPF using MVVM -


i'm trying conform mvvm structure when getting mouse position when on image in wpf application. mouse position should converted pixel location respect image.

i have working when image_mousemove in imagepositionview.xaml.cs, i'm @ bit of loss (even after trying read other threads) how achieve using mvvm structure.

i have added reference mvvmlight in hopes make task easier, have never used before..

this have far:

view:

i have added these references based on have seen:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:cmd="http://www.galasoft.ch/mvvmlight"

<usercontrol x:class="imagepixellocation.view.imagepositionview"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"     xmlns:cmd="http://www.galasoft.ch/mvvmlight"     xmlns:local="clr-namespace:imagepixellocation"     mc:ignorable="d"      d:designheight="600" d:designwidth="1000" background="white">     <grid>        <viewbox horizontalalignment="center">            <grid name="colorimage">                <image x:name="imageondisplay" source="{binding colourimage}" stretch="uniformtofill" />            </grid>        </viewbox>    </grid>  </usercontrol> 

viewmodel:

viewmodelbase exposes inofitypropertychanged , idisposable

using system.windows; using system.windows.input; using system.windows.media; using system.windows.media.imaging; using galasoft.mvvmlight;  namespace imagepixelview.viewmodel {     class imagepositionviewmodel : viewmodelbase     {          private writeablebitmap colourbitmap = null;          public imagesource colourimage         {                         {                 return this.colourbitmap;             }         }           public manualselectionviewmodel()         {             // open image writeablebitmap             string path = @"c:\some\path\to\colorimage.png";              stream imagestreamsource = new filestream(path, filemode.open, fileaccess.read, fileshare.read);             var decoder = new pngbitmapdecoder(imagestreamsource, bitmapcreateoptions.preservepixelformat, bitmapcacheoption.default);             bitmapsource source = decoder.frames[0];              int width = source.pixelwidth;             int height = source.pixelheight;             int stride = source.format.bitsperpixel / 8 * width;             byte[] data = new byte[stride * height];             source.copypixels(data, stride, 0);              this.colourbitmap = new writeablebitmap(width, height, 96.0, 96.0, source.format, null);             this.colourbitmap.writepixels(new int32rect(0, 0, width, height), data, stride, 0);         }           private void image_mousemove(object sender, mouseeventargs e)         {             bitmapsource bitmapimage = (bitmapsource)this.colourimage;              string xcoord = (e.getposition(imageondisplay).x * bitmapimage.pixelwidth / imageondisplay.actualwidth).tostring();             string ycoord = (e.getposition(imageondisplay).y * bitmapimage.pixelheight / imageondisplay.actualheight).tostring();              system.diagnostics.debug.writeline("mouse location x:" + xcoord + ", y:" + ycoord);         }      } } 

i guess main thing how access view element imageondisplay within imagepositionviewmodel.

i behaviour. first declare interface view model implement:

public interface imousecaptureproxy {     event eventhandler capture;     event eventhandler release;      void onmousedown(object sender, mousecaptureargs e);     void onmousemove(object sender, mousecaptureargs e);     void onmouseup(object sender, mousecaptureargs e); }  public class mousecaptureargs {     public double x {get; set;}     public double y { get; set; }     public bool leftbutton { get; set; }     public bool rightbutton { get; set; } } 

and here's behaviour uses it:

public class mousecapturebehavior : behavior<frameworkelement> {     public static readonly dependencyproperty proxyproperty = dependencyproperty.registerattached(         "proxy",         typeof(imousecaptureproxy),         typeof(mousecapturebehavior),         new propertymetadata(null, onproxychanged));      public static void setproxy(dependencyobject source, imousecaptureproxy value)     {         source.setvalue(proxyproperty, value);     }      public static imousecaptureproxy getproxy(dependencyobject source)     {         return (imousecaptureproxy)source.getvalue(proxyproperty);     }      private static void onproxychanged(dependencyobject d, dependencypropertychangedeventargs e)     {         if (e.oldvalue imousecaptureproxy)         {             (e.oldvalue imousecaptureproxy).capture -= oncapture;             (e.oldvalue imousecaptureproxy).release -= onrelease;         }         if (e.newvalue imousecaptureproxy)         {             (e.newvalue imousecaptureproxy).capture += oncapture;             (e.newvalue imousecaptureproxy).release += onrelease;         }     }      static void oncapture(object sender, eventargs e)     {         var behavior = sender mousecapturebehavior;         if (behavior != null)             behavior.associatedobject.capturemouse();     }      static void onrelease(object sender, eventargs e)     {         var behavior = sender mousecapturebehavior;         if (behavior != null)             behavior.associatedobject.releasemousecapture();     }      protected override void onattached()     {         base.onattached();         this.associatedobject.previewmousedown += onmousedown;         this.associatedobject.previewmousemove += onmousemove;         this.associatedobject.previewmouseup += onmouseup;     }      protected override void ondetaching()     {         base.ondetaching();         this.associatedobject.previewmousedown -= onmousedown;         this.associatedobject.previewmousemove -= onmousemove;         this.associatedobject.previewmouseup -= onmouseup;     }      private void onmousedown(object sender, mousebuttoneventargs e)     {         var proxy = getproxy(this);         if (proxy != null)         {             var pos = e.getposition(this.associatedobject);             var args = new mousecaptureargs {                 x = pos.x,                 y = pos.y,                 leftbutton = (e.leftbutton == mousebuttonstate.pressed),                 rightbutton = (e.rightbutton == mousebuttonstate.pressed)             };             proxy.onmousedown(this, args);         }     }      private void onmousemove(object sender, mouseeventargs e)     {         var proxy = getproxy(this);         if (proxy != null)         {             var pos = e.getposition(this.associatedobject);             var args = new mousecaptureargs {                 x = pos.x,                 y = pos.y,                 leftbutton = (e.leftbutton == mousebuttonstate.pressed),                 rightbutton = (e.rightbutton == mousebuttonstate.pressed)             };             proxy.onmousemove(this, args);         }     }      private void onmouseup(object sender, mousebuttoneventargs e)     {         var proxy = getproxy(this);         if (proxy != null)         {             var pos = e.getposition(this.associatedobject);             var args = new mousecaptureargs             {                 x = pos.x,                 y = pos.y,                 leftbutton = (e.leftbutton == mousebuttonstate.pressed),                 rightbutton = (e.rightbutton == mousebuttonstate.pressed)             };             proxy.onmouseup(this, args);         }     }  } 

to use behaviour add target ui element , bind object implements proxy interface. in case made mainviewmodel implement interface bind that:

<!-- canvas must have background, if it's transparent --> <canvas background="white" xmlns:i="clr-namespace:system.windows.interactivity;assembly=system.windows.interactivity">     <i:interaction.behaviors>         <behaviors:mousecapturebehavior proxy="{binding}" />     </i:interaction.behaviors> 

the view model needs provide mouse handlers behaviour call, needs provide capture/release events behaviour respond when raised view model:

public class mainviewmodel : viewmodelbase, imousecaptureproxy {     public event eventhandler capture;     public event eventhandler release;      public void onmousedown(object sender, mousecaptureargs e) {...}     public void onmousemove(object sender, mousecaptureargs e) {...}     public void onmouseup(object sender, mousecaptureargs e) {...} } 

update: should self-evident, in case not: sender pass in capture , release events should same 1 received via mousedown/move/up handlers. event args passed capture/receive aren't used , can null.


Comments