Fabulous.WPF icon indicating copy to clipboard operation
Fabulous.WPF copied to clipboard

ShowDialog

Open JordanMarr opened this issue 5 years ago • 9 comments

First off, I love the idea of having a Fabulous.WPF that doesn't have the baggage of Xamarin for apps that only need to target WPF. This is very cool!

I have been doing a lot of Revit add-ins where I often need to load a window with ShowDialog. Any thoughts on how to load this way? I made a very quick attempt (without knowing what I was doing) to change WPFHost.SetRootView to call ShowDialog, but the blocking nature of the modal window caused issues (it seems to be preventing something else from initializing). The window loaded, but when I clicked a button I got "do no call dispatch during initialization"; so I am assuming that the modal window blocked initialization.

Maybe there could be a different way to run the app as a modal window.

JordanMarr avatar Dec 09 '19 22:12 JordanMarr

I removed the call to "window.Show()" completely in the WPFHost SetRootView and called ShowDialog from my app. I was able to open and close the dialog multiple times from my Revit add-in -- (obviously no BSOD issues as I was having with Xamarin). So that makes this library viable for use with Revit add-in development!

So then it comes down to getting more WPF controls ported over to the Fabulous.WPF.View module. The xaml page that I wanted to try to create first requires the DockPanel, RadioButton, Border and DataGrid (or at least something comparable to a grid).

JordanMarr avatar Dec 12 '19 07:12 JordanMarr

Oh great! Fabulous expects a single root by default. But if you found a way that suits you that's awesome. :)

So then it comes down to getting more WPF controls ported over to the Fabulous.WPF.View module. The xaml page that I wanted to try to create first requires the DockPanel, RadioButton, Border and DataGrid (or at least something comparable to a grid).

For that, you will need to run the generator project with the following arguments

-m src\Fabulous.WPF\WPF.json -o src\Fabulous.WPF\WPF.fs -d

Once you do that, a file called 1-assembly-types.json will contain all the information that Fabulous.CodeGen found in the WPF dlls. If the controls are in there, you can add to src\Fabulous.WPF\WPF.json:

{
  "type": "System.Windows.Controls.Border",
  "properties": [

  ]
},

This will make the generator generates a wrapper for Border without any property. To add a property, change it to:

{
  "type": "System.Windows.Controls.Border",
  "properties": [
    {
        "source": "CornerRadius"
    }
  ]
},

After compiling everything, you will be able to use it:

View.Border(
    cornerRadius = System.Windows.CornerRadius(15)
)

This a mostly trial-and-error process. Don't hesitate to look at the console output of the generator. It will report anything wrong. Also, files like 1-assembly-types.json will give an insight into what's going on inside Fabulous.CodeGen.

TimLariviere avatar Dec 12 '19 08:12 TimLariviere

Also, there are quite a few values you can override in src\Fabulous.WPF\WPF.json, if need be. https://github.com/fsprojects/Fabulous/blob/master/Fabulous.CodeGen/src/Fabulous.CodeGen/Models.fs

TimLariviere avatar Dec 12 '19 08:12 TimLariviere

The View.Border is generating, and I can assign properties.
The problem is that I'm trying to add the "Child" property, which is of type UIElement, but it won't let me assign a TextbBlock to it:

View.Border(
   child = View.TextBlock(text = "asdf"),
   borderBrush = Brushes.Red
)

Property metadata:

{
            "type": "System.Windows.Controls.Border",
            "properties": [
                {
                    "source": null,
                    "name": "Child",
                    "inputType": "System.Windows.UIElement",
                    "defaultValue": "null"
                },
                {
                    "source": "CornerRadius",
                    "defaultValue": "System.Windows.CornerRadius(0.)"
                },
                {
                    "source": "BorderThickness",
                    "defaultValue": "System.Windows.Thickness(0.)"
                },
                {
                    "source": "Padding",
                    "defaultValue": "System.Windows.Thickness(0.)"
                },
                {
                    "source": "BorderBrush",
                    "defaultValue": "null"
                },
                {
                    "source": "Background",
                    "inputType": "System.Windows.Media.Brush",
                    "defaultValue": "null"
                }
            ]
        }

JordanMarr avatar Dec 13 '19 06:12 JordanMarr

Could you try to declare System.Windows.UIElement (with CanBeInstantiated = false) in the JSON file? (no property required)

When a type is declared, the Generator automatically replaces the type (when required by a property) by ViewElement (which allows using child = View.TextBlock() instead of child = new System.Windows.Controls.TextBlock()).

TimLariviere avatar Dec 13 '19 06:12 TimLariviere

It worked!

I had to put UIElement above FrameworkElement though or else the generated code was in the wrong order.

JordanMarr avatar Dec 13 '19 07:12 JordanMarr

I am unsurprisingly stuck on the DockPanel.Dock attached property. I don't know how it would be possible for child elements to display attached properties in their c'tors; it seems like a more reasonable approach might be for View.DockPanel c'tor to have "childrenTop", "childrenLeft", "childrenRight" and "childrenLeft" lists in addition to "children". Then anything in "childrenTop", for example, could be added to the DockPanel's Dock dependency property.

JordanMarr avatar Dec 14 '19 04:12 JordanMarr

On second thought, the "LastChildFill" property requires there be one list. Maybe Children could be a list of a Dock discriminated union:

type DockDirection =
  | Top of ViewElement
  | Left of ViewElement
  | Right of ViewElement
  | Bottom of ViewElement

Then DockPanel Children could be a DockDirection list.

JordanMarr avatar Dec 14 '19 05:12 JordanMarr

Sorry, I should have looked at what already exists in Fabulous for attached properties (Grid / .GridRow method)!

JordanMarr avatar Dec 14 '19 07:12 JordanMarr