fsprojects / FsXaml

F# Tools for working with XAML Projects
http://fsprojects.github.io/FsXaml/
MIT License
171 stars 48 forks source link

Suggestion: alternative way to wrap XAML(?) #29

Closed ruxo closed 8 years ago

ruxo commented 8 years ago

I've developed my own XAML wrapper in F#. It makes implementing User Control in F# more easier (is there a way to do it with FsXaml type provider?). My wrapper looks like this:

// instead of type MainWindow = XAML<"Sample.xaml">
type MainWindow() as me =
  inherit Window()
  do me.InitializeCodeBehind("Sample.xaml")

(For full example, see https://github.com/ruxo/WpfFs/blob/master/README.md )

Is this feature interested enough to put in FsXaml library?

(Sorry if this style has been discussed before, I'm new to FsXaml library)

ReedCopsey commented 8 years ago

@ruxo Thanks for this - I'll try to carve out some time to look into it in detail.

It looks like you figured out how to get the xaml loader to load directly into the root object, as well. That's something I'll definitely consider stealing - it'd make FsXaml's type provider better...

As for adding the ability to subclass, it's definitely something I'll look into - I think that may make a lot of sense for integrating in some manner. I need to spend some time with your library in detail to figure out how it's all working.

That being said, would you be willing to relicense or dual license under Apache 2, so I can include the code directly? Most of the core F# projects are apache licensed, so I followed suit with this library.

ruxo commented 8 years ago

Thank you. Glad my idea can help :)

For the license, I'll make change later. But here is a code snippet that I think you can just used to do the trick.

    let private loadStreamInternal(reader: XamlXmlReader, rootObject: obj option) =
        let writerSettings = XamlObjectWriterSettings()
        match rootObject with
        | Some root -> writerSettings.RootObjectInstance <- root
        | None -> ()

        use writer = new XamlObjectWriter(reader.SchemaContext, writerSettings)

        while reader.Read() do
            writer.WriteNode(reader)

        writer.Result

    let private loadWpfInternal (xamlContent: string) (rootObject: obj option) :obj =
        let stream = new StringReader(xamlContent)
        use reader = new XamlXmlReader(stream, XamlReader.GetWpfSchemaContext())
        loadStreamInternal(reader, rootObject)

If we can load XAML string from resource and we have the root object, we can apply XAML to the root object by calling loadWpfInternal xamlContent (Some ourWpfObject), which is essentially what InitializeCodeBehind method finally calls.

ReedCopsey commented 8 years ago

@ruxo Just wanted to follow up - I've been working on this, and have a prototype that now allows for:

type MainViewBase = XAML<"MainView.xaml", true>
type MainView() as self =
    inherit MainViewBase()

    do
        let showMessage _ =
            System.Windows.MessageBox.Show "You double clicked on Full Name!"
            |> ignore

        self.Loaded.Subscribe (fun _ -> self.tbFullName.MouseDoubleClick.Subscribe showMessage |> ignore) |> ignore

The nice thing here is you still get the advantages of the type provider (automatic handling of named elements - see tbFullname above), but a way to write "code behind" more naturally. This will likely eliminate the need for the ViewController "hack" in FsXaml today, as well.

I'm hoping to clean this up and get it posted here soon - will likely work on FsXaml 2.0 pre using this technique, since it's not backwards compatible with the current library.

ruxo commented 8 years ago

Thank you for head up. This looks awesome :D. If there's anything I can help please say so.

JohanLarsson commented 8 years ago

@ReedCopsey share the prototype before cleaning it up?

ReedCopsey commented 8 years ago

@JohanLarsson Pushing code in a minute - planning a prerelease nuget package shortly.

ReedCopsey commented 8 years ago

@JohanLarsson Nuget has a prerelease with this - please feel free to test and give feedback.

ReedCopsey commented 8 years ago

@ruxo Can you look at #38 ?

Does that happen with your approach, as well? I'm using the technique you spelled out in FsXaml 2.0, and it's now causing this to occur. I'm not sure how to work around it.