如何在F#中写下WPF自定义控件?

发布于 2025-01-26 16:12:45 字数 5567 浏览 2 评论 0原文

我试图了解如何用F#编写WPF自定义控件。

例如,我有以下C#代码,用于在画布上拖放(在C#中)。它从列表框继承。我不是在寻找任何人来重写此事。但是,由于没有XAML可以处理,我对如何在Elmish.wpf中实施它感到茫然。 (我相信自定义控件没有XAML接口)。

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);
                }              
                ));

    }
}

关于如何处理这一新手的任何建议将不胜感激。

tia

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文