在F#中,我无法执行请求对象中描述的操作。
缺失的一点是C#事件的F#实现,声明如下:
public event RoutedEventHandler DataChanged
{
add { base.AddHandler(ucData.DataChangedEvent, value); }
remove { base.RemoveHandler(ucData.DataChangedEvent, value); }
}
我如何在F#中做到这一点?
注意:在输出wpf测试窗口中,用户控件"ucData"可以工作(属性和TextBox之间已经实现了内部绑定),但当我"按代码"或"按窗口"更改"Data"属性的值(用键盘在wpf窗口中显示的用户控件上输入)时,位于测试wpf窗口内的"DataChanged"事件的侦听器不会触发/激发。
谢谢(一如既往)。
用户控件"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
这里有"ucData"的完整功能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>