I am trying to understand how a wpf custom control could be written in F#.
As an example, I have the following C# code for a drag and drop on a canvas (in C#). It inherits from ListBox. I'm not looking for anybody to rewrite this. But I'm at a loss as to how it would be implemented in Elmish.wpf since there is no xaml to deal with. (I believe a Custom Control does not have a XAML interface).
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Stargate.XI.Client.Views.CustomControls
{
public delegate void DropCompletedEventHandler(object sender, DropCompletedEventArgs e);
// To add a custom DropCompletedEvent to an ItemsControl, I would either have to have an attached property, as in
// https://stackoverflow.com/questions/15134514/attached-behavior-handling-an-attached-event-in-wpf
// or subclass an ItemsControl as below. Creating a simple custom control, like here, seems cleaner.
// Note: ItemsControl can't select items, only present collections. Only a Selector or one of it's descendants can select items
// Hence, only the ListBox or its derivative,ListView, have Selector's.
public class ChartCanvas : ListBox
{
public event EventHandler PlayMusicEvent;
public event EventHandler PauseMusicEvent;
public event EventHandler StopMusicEvent;
public event EventHandler DisposeMusicEvent;
public event EventHandler DisposePosterEvent;
#region DropCompletedEvent
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent DropCompletedEvent = EventManager.RegisterRoutedEvent(
"DropCompleted", RoutingStrategy.Bubble, typeof(DropCompletedEventHandler), typeof(ChartCanvas));
// Provide CLR accessors for the event. The RoutedEventHandler, e.g., "DropCompleted" is used in the xaml declaration for the ImageCanvas.
public event DropCompletedEventHandler DropCompleted
{
add { AddHandler(DropCompletedEvent, value); }
remove { RemoveHandler(DropCompletedEvent, value); }
}
// This method raises the DropCompleted event
public void RaiseDropCompletedEvent(object datatype)
{
RaiseEvent(new DropCompletedEventArgs(DropCompletedEvent, datatype));
}
#endregion
public ChartCanvas()
{
AllowDrop = true;
DragEnter += IC_DragEnter;
Drop += IC_Drop;
DragOver += IC_DragOver;
DragLeave += IC_DragLeave;
}
private void IC_DragLeave(object sender, DragEventArgs e)
{
e.Handled = true;
}
private void IC_DragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
private void IC_Drop(object sender, DragEventArgs e)
{
var data = e.Data.GetData(DataFormats.Text);
var dragSource = e.Data.GetData("DragSource");
RaiseDropCompletedEvent(data);
}
private void IC_DragEnter(object sender, DragEventArgs e)
{
e.Handled = true;
}
#region PlayMovie
private ICommand _playMovie;
public ICommand PlayMovieCommand
{
get
{
if (_playMovie == null)
{
_playMovie = new RelayCommand(
p => true,
p => this.PlayMovie());
}
return _playMovie;
}
}
private void PlayMovie()
{
PlayMusicEvent?.Invoke(this, EventArgs.Empty);
}
#endregion
#region PauseMovie
private ICommand _pauseMovie;
public ICommand PauseMovieCommand
{
get
{
if (_pauseMovie == null)
{
_pauseMovie = new RelayCommand(
p => true,
p => this.PauseMovie());
}
return _pauseMovie;
}
}
private void PauseMovie()
{
PauseMusicEvent?.Invoke(this, EventArgs.Empty);
}
#endregion
#region StopMovie
private ICommand _stopMovie;
public ICommand StopMovieCommand
{
get
{
if (_stopMovie == null)
{
_stopMovie = new RelayCommand(
p => true,
p => this.StopMovie());
}
return _stopMovie;
}
}
private void StopMovie()
{
StopMusicEvent?.Invoke(this, EventArgs.Empty);
}
#endregion
public bool Dispose
{
get { return (bool)GetValue(DisposeProperty); }
set { SetValue(DisposeProperty, value); }
}
// Using a DependencyProperty as the backing store for Dispose. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DisposeProperty =
DependencyProperty.Register("Dispose", typeof(bool), typeof(ChartCanvas), new PropertyMetadata(false,
(s,e) =>
{
ChartCanvas chartcanvas = s as ChartCanvas;
chartcanvas.DisposeMusicEvent?.Invoke(chartcanvas, EventArgs.Empty);
chartcanvas.DisposePosterEvent?.Invoke(chartcanvas, EventArgs.Empty);
}
));
}
}
Any suggestions to this newbie as to how to approach this would be much appreciated.
TIA