How to approach writing a WPF Custom Control in F#?

92 views Asked by At

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

0

There are 0 answers