F#WPF:用户控件:DependencyProperty配有RegisterRoutedEvent

时间:2015-02-24 20:18:52

标签: wpf f# event-handling wpf-controls dependency-properties

在F#中,我无法执行请求对象中描述的操作。

缺少的点是声明如下的C#事件的F#实现:

public event RoutedEventHandler DataChanged
{ 
 add { base.AddHandler(ucData.DataChangedEvent, value); }
 remove { base.RemoveHandler(ucData.DataChangedEvent, value); }
}

我如何在F#中做到这一点?

注意:在输出wpf测试窗口中,用户控件“ucData”有效(内部绑定已在property和TextBox之间实现),但是位于测试wpf窗口内的“DataChanged”事件的监听器不会触发/触发当我更改“数据”属性“by-code”或“by-window”的值时(在wpf窗口内显示的用户控件上输入键盘)。

谢谢(总是如此)。

用户控件“ucData”的属性:

static let  OnDataPropertyChanged (sender:DependencyObject) (e:DependencyPropertyChangedEventArgs) =
    let control = unbox<ucData>(sender)
    let newValue = unbox<double>(e.NewValue)
    let oldValue = unbox<double>(e.OldValue)
    System.Console.WriteLine
        (sprintf 
            ">>> OnPropertyChanged 'ucData':'Data': Control Name: %s; Value: %f --> %f <<<" 
            control.Name oldValue newValue )
    let argsEvent = new RoutedPropertyChangedEventArgs<double>(oldValue, newValue)
    argsEvent.RoutedEvent <- ucData.DataChangedEvent  // I get an ERROR here!!!!
    control.RaiseEvent(argsEvent)


static let OnCoerceDataProperty (sender:DependencyObject) (data:obj) =
    let control = unbox<ucData>(sender)
    let value = unbox<double>(data)
    System.Console.WriteLine
        (sprintf 
            ">>> OnCoerceValue 'ucData':'Data': Control Name: %s; Value: : %f <<<" 
            control.Name value )
    box(value)

static let OnValidateDataProperty (data:obj) =
    System.Console.WriteLine
        (sprintf 
            ">>> OnValidateValue 'ucData':'Data': Data %s <<<" 
            (data.ToString()) )
    data.GetType() = typeof<double>

static let dpData = 
    DependencyProperty.Register("Data",typeof<double>, typeof<ucData>, 
        new FrameworkPropertyMetadata( 0.0,
            FrameworkPropertyMetadataOptions.Inherits,
            new PropertyChangedCallback(OnDataPropertyChanged),
            new CoerceValueCallback(OnCoerceDataProperty) ),
        new ValidateValueCallback(OnValidateDataProperty) )

static member DataProperty = dpData

[<Description("Specify the Numerical Data"); Category("UserData")>]
member x.Data
    with get() = 
        let res = x.GetValue(ucData.DataProperty) 
        (res :?> double)
    and set (v:double) = 
        x.SetValue(ucData.DataProperty, v )

用户控制事件“ucData”:

static let reDataChangedEvent =
    EventManager.RegisterRoutedEvent
        ("DataChanged", RoutingStrategy.Bubble, 
            typeof<RoutedPropertyChangedEventHandler<double>>, typeof<ucData>)

let dataChangedEvent = 
    let e = new  Event<RoutedPropertyChangedEventHandler<double>,RoutedPropertyChangedEventArgs<double>>() 
    // Equialent to: 
    //    public event RoutedPropertyChangedEventHandler<double> DataChanged
    //    {
    //       add { AddHandler(DataChangedEvent, value); }
    //       remove { RemoveHandler(DataChangedEvent, value); }
    //    }
    // where DataChangedEvent is so defined:
    //    public static readonly RoutedEvent DataChangedEvent;        
    e

[<CLIEvent>]
static member DataChangedEvent with get() = reDataChangedEvent   // I get an ERROR here!!!

[<CLIEvent>]
member x.DataChanged = dataChangedEvent.Publish 

1 个答案:

答案 0 :(得分:0)

这里有“ucData”的FULL FUNCTIONAL C#版本(F#仍然存在C#和F#之间“事件”定义不同的问题):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace UCLibrary
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class ucInput : UserControl
    {

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        public static DependencyProperty DescriptionProperty;

        public static DependencyProperty DataProperty;

        public static DependencyProperty UnitOfMeasureProperty;

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        public static readonly RoutedEvent DescriptionChangedEvent;

        public static readonly RoutedEvent DataChangedEvent;

        public static readonly RoutedEvent UnitOfMeasureChangedEvent;

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        private static void OnDescriptionChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
        {
            ucInput control = (ucInput)sender;
            string oldValue = (string)e.OldValue;
            string newValue = (string)e.NewValue;

            string result = string.Format(
                ">>> OnPropertyChanged 'ucInput':'Description': Control Name: {0}; Value: {1} --> {2} <<<",
                control.Name, 
                oldValue, 
                newValue);

            System.Console.WriteLine(result);

            RoutedPropertyChangedEventArgs<string> argsEvent =
                new RoutedPropertyChangedEventArgs<string>(oldValue, newValue);

            argsEvent.RoutedEvent = ucInput.DescriptionChangedEvent;

            control.RaiseEvent(argsEvent);

        }

        private static void OnDataChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ucInput control = (ucInput)sender;
            double oldValue = (double)e.OldValue;
            double newValue = (double)e.NewValue;

            string result = string.Format(
                ">>> OnPropertyChanged 'ucInput':'Data': Control Name: {0}; Value: {1} --> {2} <<<",
                control.Name,
                oldValue,
                newValue);

            System.Console.WriteLine(result);

            RoutedPropertyChangedEventArgs<double> argsEvent =
                new RoutedPropertyChangedEventArgs<double>(oldValue, newValue);
            argsEvent.RoutedEvent = ucInput.DataChangedEvent;

            control.RaiseEvent(argsEvent);

        }

        private static void OnUnitOfMeasureChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ucInput control = (ucInput)sender;
            string oldValue = (string)e.OldValue;
            string newValue = (string)e.NewValue;

            string result = string.Format(
                ">>> OnPropertyChanged 'ucInput':'UnitOfMeasure': Control Name: {0}; Value: {1} --> {2} <<<",
                control.Name,
                oldValue,
                newValue);

            System.Console.WriteLine(result);

            RoutedPropertyChangedEventArgs<string> argsEvent =
                new RoutedPropertyChangedEventArgs<string>(oldValue, newValue);
            argsEvent.RoutedEvent = ucInput.UnitOfMeasureChangedEvent;

            control.RaiseEvent(argsEvent);

        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        private static object OnCoerceDescriptionProperty(DependencyObject sender, Object data)
        {
            ucInput control = (ucInput)sender;
            string value = (string)data;

            value = value + ":";

            string result = string.Format(
                ">>> OnCoerceValue 'ucInput':'UnitOfMeasure': Control Name: {0}; Value: {1} <<<",
                control.Name,
                value);

            System.Console.WriteLine(result);

            return (object)value;

        }

        private static object OnCoerceDataProperty(DependencyObject sender, Object data)
        {
            ucInput control = (ucInput)sender;
            double value = (double)data;

            string result = string.Format(
                ">>> OnCoerceValue 'ucInput':'UnitOfMeasure': Control Name: {0}; Value: {1} <<<",
                control.Name,
                value);

            System.Console.WriteLine(result);

            return (object)value;

        }

        private static object OnCoerceUnitOfMeasureProperty(DependencyObject sender, Object data)
        {
            ucInput control = (ucInput)sender;
            string value = (string)data;

            value = "[" + value + "]";

            string result = string.Format(
                ">>> OnCoerceValue 'ucInput':'UnitOfMeasure': Control Name: {0}; Value: {1} <<<",
                control.Name,
                value);

            System.Console.WriteLine(result);

            return (object)value;

        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        private static bool OnValidateDescriptionProperty(Object data)
        {

            string result = string.Format(
                ">>> OnValidateValue 'ucInput':'UnitOfMeasure': TypeOf: {0} <<<",
                data.GetType().ToString());

            System.Console.WriteLine(result);

            return ( data.GetType() == typeof(String) );

        }

        private static bool OnValidateDataProperty(Object data)
        {

            string result = string.Format(
                ">>> OnValidateValue 'ucInput':'UnitOfMeasure': TypeOf: {0} <<<",
                data.GetType().ToString());

            System.Console.WriteLine(result);

            return (data.GetType() == typeof(Double));

        }

        private static bool OnValidateUnitOfMeasureProperty(Object data)
        {

            string result = string.Format(
                ">>> OnValidateValue 'ucInput':'UnitOfMeasure': TypeOf: {0} <<<",
                data.GetType().ToString());

            System.Console.WriteLine(result);

            return (data.GetType() == typeof(String));

        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        static ucInput()
        {

            // ------------------------------------------------------------------------------------------ //

            DescriptionProperty =
                DependencyProperty.Register(
                    "Description", typeof(string), typeof(ucInput),
                    new FrameworkPropertyMetadata("Description",
                           FrameworkPropertyMetadataOptions.Inherits,
                           new PropertyChangedCallback(OnDescriptionChanged),
                           new CoerceValueCallback(OnCoerceDescriptionProperty)),
                     new ValidateValueCallback(OnValidateDescriptionProperty)
                    );

            DataProperty =
                DependencyProperty.Register(
                    "Data", typeof(double), typeof(ucInput),
                    new FrameworkPropertyMetadata(0.0,
                           FrameworkPropertyMetadataOptions.Inherits,
                           new PropertyChangedCallback(OnDataChanged),
                           new CoerceValueCallback(OnCoerceDataProperty)),
                     new ValidateValueCallback(OnValidateDataProperty)
                    );

            UnitOfMeasureProperty =
                DependencyProperty.Register(
                "UnitOfMeasure", typeof(string), typeof(ucInput),
                new FrameworkPropertyMetadata("UM",
                           FrameworkPropertyMetadataOptions.Inherits,
                           new PropertyChangedCallback(OnUnitOfMeasureChanged),
                           new CoerceValueCallback(OnCoerceUnitOfMeasureProperty)),
                     new ValidateValueCallback(OnValidateUnitOfMeasureProperty)
                );

            // ------------------------------------------------------------------------------------------ //

            DescriptionChangedEvent = 
                EventManager.RegisterRoutedEvent(
                    "DescriptionChanged", RoutingStrategy.Bubble,
                    typeof(RoutedPropertyChangedEventHandler<string>), typeof(ucInput));

            DataChangedEvent =
                EventManager.RegisterRoutedEvent(
                    "DataChanged", RoutingStrategy.Bubble,
                    typeof(RoutedPropertyChangedEventHandler<double>), typeof(ucInput));

            UnitOfMeasureChangedEvent =
                EventManager.RegisterRoutedEvent(
                    "UnitOfMeasureChanged", RoutingStrategy.Bubble,
                    typeof(RoutedPropertyChangedEventHandler<string>), typeof(ucInput));

        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        public ucInput()
        {
            InitializeComponent();
        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        [Description("Description of the Numerical Data"), Category("UserData")]
        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        [Description("Specify the Numerical Data"), Category("UserData")]
        public double Data
        {
            get { return (double)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        [Description("Specify the 'Unit of Measure'"), Category("UserData")]
        public string UnitOfMeasure
        {
            get { return (string)GetValue(UnitOfMeasureProperty); }
            set { SetValue(UnitOfMeasureProperty, value); }
        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

        [Description("Property 'Description' Changed"), Category("UserData")]
        public event RoutedPropertyChangedEventHandler<string> DescriptionChanged
        {
            add { AddHandler (DescriptionChangedEvent, value); }
            remove { RemoveHandler(DescriptionChangedEvent, value); }
        }

        [Description("Property 'Data' Changed"), Category("UserData")]
        public event RoutedPropertyChangedEventHandler<double> DataChanged
        {
            add { AddHandler(DataChangedEvent, value); }
            remove { RemoveHandler(DataChangedEvent, value); }
        }

        [Description("Property 'UnitOfMeasure' Changed"), Category("UserData")]
        public event RoutedPropertyChangedEventHandler<double> UnitOfMeasureChanged
        {
            add { AddHandler(UnitOfMeasureChangedEvent, value); }
            remove { RemoveHandler(UnitOfMeasureChangedEvent, value); }
        }

        // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //

    }
}

下面是XAML

<UserControl x:Class="UCLibrary.ucInput"
         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:local="clr-namespace:UCLibrary" 
         mc:Ignorable="d" 
         d:DesignHeight="30" d:DesignWidth="507">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100*" MinWidth="100"/>
        <ColumnDefinition Width="Auto" MinWidth="80"/>
        <ColumnDefinition Width="70*" MinWidth="70"/>
    </Grid.ColumnDefinitions>
    <Label Name="lblDescription" 
           Margin="3"
           Grid.Column="0"
           Content="{Binding Description, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ucInput}}}"/>
    <TextBox Name="txtData" 
             Margin="3"
             Grid.Column="1"
             Text="{Binding Data, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ucInput}}, StringFormat=N}">
    </TextBox>
    <Label Name="lblUnitOfMeasure" 
           Margin="3"
           Grid.Column="2"
           Content="{Binding UnitOfMeasure, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ucInput}}}"/>
</Grid>

相关问题