Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Property in F# Default Value does not match

I am trying to convert a C# Dependency Property that limits the maximum length of text entered into a ComboBox to F#. The program is a MVVM program that uses F# for the model and viewmodel, and C# for the view. the working C# code is this:

public class myComboBoxProperties
    {
        public static int GetMaxLength(DependencyObject obj)
        {
            return (int)obj.GetValue(MaxLengthProperty);
        }

        public static void SetMaxLength(DependencyObject obj, int value)
        {
            obj.SetValue(MaxLengthProperty, value);
        }

        // Using a DependencyProperty as the backing store for MaxLength. This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxLengthProperty =
            DependencyProperty.RegisterAttached("MaxLength",
            typeof(int),
            typeof(myComboBoxProperties),
            new UIPropertyMetadata(OnMaxLengthChanged));

        private static void OnMaxLengthChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (obj is ComboBox)
            {
                ComboBox comboBox = (ComboBox)obj;

                comboBox.Loaded += (sender, e) =>
                {
                    TextBox textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;

                    if (textBox != null)
                    {
                        textBox.SetValue(TextBox.MaxLengthProperty, args.NewValue);
                    }
                };
            }
        }
    }

The F# code is this:

type myComboBoxProperties() =

    static let OnMaxLengthChanged  (myobj1 : DependencyObject, args : DependencyPropertyChangedEventArgs)  =

        let comboBox = myobj1 :?> ComboBox

        comboBox.Loaded.Subscribe (fun _ -> 
                                    let textBox : TextBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) :?> TextBox 
                                    match textBox with
                                    | null -> ()
                                    |_ -> textBox.SetValue(TextBox.MaxLengthProperty, args.NewValue))

    static let MaxLengthProperty = DependencyProperty.RegisterAttached("MaxLength", typeof<int>, typeof<myComboBoxProperties>, new UIPropertyMetadata(OnMaxLengthChanged))

    static member GetMaxLength (myobj : DependencyObject) = myobj.GetValue(MaxLengthProperty) :?> int

    static member SetMaxLength (myobj : DependencyObject, value : int) = myobj.SetValue(MaxLengthProperty, value)

The problem I am having is that the XAML error I get is:

Default value type does not match type of property MaxLength

What am I doing wrong?

like image 364
Mark W Avatar asked May 16 '15 16:05

Mark W


People also ask

What is a dependency property?

A dependency property can reference a value through data binding. Data binding works through a specific markup extension syntax in XAML, or the Binding object in code. With data binding, determination of the final property value is deferred until run time, at which time the value is obtained from a data source.

What is dependency property in UWP?

A dependency property represents or supports a specific feature of the programming model for defining a Windows Runtime app with XAML for UI and C#, Microsoft Visual Basic or Visual C++ component extensions (C++/CX) for code. These features include: Data binding. Styles. Storyboarded animations.

What is the difference between property and dependency property?

A dependency property provides functionality that extends the functionality of a property as opposed to a property that is backed by a field. Often, each such functionality represents or supports a specific feature of the overall WPF set of features.


1 Answers

You could try this

open System.Windows
open System.Windows.Controls

type MyComboBoxProperties() =

  static let OnMaxLengthChanged  (myobj1 : DependencyObject) (args : DependencyPropertyChangedEventArgs) =

    let comboBox = myobj1 :?> ComboBox

    comboBox.Loaded.Add (
      fun _ -> 
        let textBox : TextBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) :?> TextBox 
        match textBox with
        | null -> ()
        |_ -> textBox.SetValue(TextBox.MaxLengthProperty, args.NewValue)
      )

  static let MaxLengthProperty = 
    DependencyProperty.RegisterAttached(
      "MaxLength", 
      typeof<int>, 
      typeof<MyComboBoxProperties>, 
      UIPropertyMetadata(0, PropertyChangedCallback OnMaxLengthChanged)
      )

  static member GetMaxLength (myobj : DependencyObject) = myobj.GetValue(MaxLengthProperty) :?> int

  static member SetMaxLength (myobj : DependencyObject, value : int) = myobj.SetValue(MaxLengthProperty, value)

The key difference to your code is this UIPropertyMetadata(0, PropertyChangedCallback OnMaxLengthChanged) that converts OnMaxLengthChanged into a PropertyChangedCallback.

But it feels odd to me that you subscribe to the .Loaded even each time the max value you change. I suspect you only like to subscribe the first time?

like image 116
Just another metaprogrammer Avatar answered Sep 17 '22 17:09

Just another metaprogrammer