Auseinandersetzung eines durchschnittlichen Programmierer mit funktionaler Programmierung unter F#. Da Deutsch nicht meine Muttersprache ist, bin ich für Hinweise auf Fehler sehr dankbar.
F# Wpf MVVM. Mouse Tracking with AttachedProperty.
Seit letztem Beitrag habe ich überlegt, wie man die Hindernisse einfach per Maus ziehen (bei gedrückter linker Maustaste) erstellen kann.
Die zweite Herausforderung bestand in der Mausklick-Verarbeitung im Zusammenhang mit der Positionsbestimmung des Mauszeigers. Man sollte per Mausklick entweder ein Chip auswählen können oder ein Hindernis an der entsprechenden Position zu zeichnen oder zu löschen.
Nicht zu vergessen wir sind im MVVM-Land und Code-Behind ist nicht erwünscht. In diesem Fall kann die AttachedProperty eine mögliche Option sein.
//MouseTrack.fs
//NO GUARANTEE. I'm not sure that using of the Event class at this point is allowed.
namespace FSharpWpfMvvmTemplate.AttachedProperty
open System.Windows
open System.Windows.Input
// The type represents just the action that should be executed
// upon the occurrence of PreviewMouseMove event.
type TrackMouse = {action : Point -> unit}
type TrackMouseBehavior() =
let mutable startTrack = false
let mutable endTrack = true
static let mutable TrackPositionProperty : DependencyProperty =
DependencyProperty.RegisterAttached
("TrackPosition", typeof<TrackMouse>, typeof<TrackMouseBehavior>,
new PropertyMetadata(null, new PropertyChangedCallback(TrackMouseBehavior.OnPropertyChanged)))
static member OnPropertyChanged (d:DependencyObject) (e:DependencyPropertyChangedEventArgs) =
let element = d :?> UIElement
if e.NewValue <> null then
let trackMouse = e.NewValue :?> TrackMouse
let trackFunc = TrackMouseBehavior.MouseTrack trackMouse element
// First when the left mouse button is already pressed and the mouse is moved,
// until the left mouse button is released.
element.PreviewMouseLeftButtonDown
|> Event.map (fun args -> args :> MouseEventArgs)
|> Event.merge element.PreviewMouseMove
|> Event.filter (fun args -> args.LeftButton = MouseButtonState.Pressed)
|> Event.add (fun args -> func(args))
static member GetTrackPosition(d:DependencyObject) =
d.GetValue(TrackPositionProperty) :?> TrackMouse
static member SetTrackPosition(d:DependencyObject, value : TrackMouse) =
d.SetValue(TrackPositionProperty, value)
static member MouseTrack(trackPos : TrackMouse) (element:UIElement) (mouseEventArgs : MouseEventArgs ) =
let point = mouseEventArgs.GetPosition(element)
trackPos.action point
Im ViewModel wird die AddPoint-Methode definiert, die im TrackMouse-Type gekapsellt an der TrackMouseMove-AttachedProperty übergeben wird.
// JumpSearchViewModel.fs
type JumpSearchViewModel() as x=
class
...
let mutable mazePath = String.Empty
let mutable obstacles = set[]
let mutable env : MazeEnvironment = empty
...
let AddPointToPath (x, y) wallSize =
let xf, yf = (float x) * wallSize, (float y) * wallSize
let v = sprintf "M%f,%fV%f" xf yf (yf + wallSize)
let h= sprintf " H%fV%fH%f" (xf + wallSize) yf xf
sprintf "%s%s%s" mazePath v h
member x.AddPoint (point : Point) =
if not env.IsEmpty && not timer.IsEnabled && x.VerifyX() = null && x.VerifyY() = null then
let cellPos (posx, posy) = (posx / 20.0 |> int), (posy / 20.0 |> int)
let pointX, pointY = cellPos (point.X, point.Y)
if pointX <= x.MazeX - 1 && pointY <= x.MazeY - 1 then
//check if the mouse click hit the start or the finish coin position.
match (pointX, pointY) = cellPos (env.coinX, env.coinY), (pointX, pointY) = cellPos (env.targetX, env.targetY) with
| true, _ -> selectedCoin <- Start (env.coinX, env.coinY)
|_, true -> selectedCoin <- Finish (env.targetX, env.targetY)
| _ ->
obstacles <- Set.add (pointX, pointY) obstacles
mazePath <- AddPointToPath (pointX, pointY) x.WallSize
x.MazeData <- Geometry.Parse(mazePath)
//maze path geometry.
member x.MazeData
with get () = mazeGeometry
and set value =
mazeGeometry <- value
base.RaisePropertyChangedEvent(<@x.MazeData@>)
// Get the TrackMouse action that should be executed.
member x.TrackMouseMove
with get () = {action = x.AddPoint}
...
Der Kommentar wurde von einem Blog-Administrator entfernt.
AntwortenLöschen