Skip to content

Commit

Permalink
+ DataTemplateSelector (not working)
Browse files Browse the repository at this point in the history
+ IValueConverter (don't know if needed)
  • Loading branch information
YkTru committed Sep 21, 2024
1 parent be55d06 commit e4e7720
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 36 deletions.
43 changes: 42 additions & 1 deletion src/Samples/SubModelSelectedItem.Core/FsWPF.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,45 @@ open Form
type ComponentsTemplateSelector() =
inherit DataTemplateSelector()

// Properties for each DataTemplate
member val TextBox_DT: DataTemplate = null with get, set
member val CheckBox_DT: DataTemplate = null with get, set
member val ComboBox_DT: DataTemplate = null with get, set

override this.SelectTemplate(item: obj, container: DependencyObject) : DataTemplate =
match item with
| :? Form.Components as component_ ->
match component_ with
| Form.Components.TextBox _ -> this.TextBox_DT
| Form.Components.CheckBox _ -> this.CheckBox_DT
| Form.Components.ComboBox _ -> this.ComboBox_DT
| _ -> null


// not working; idea taken from "https://github.com/elmish/Elmish.WPF/issues/270#issuecomment-687329493"
type GetComponentsVMToResource() =
let toVM =
function
| TextBox a -> a |> box
| CheckBox a -> a |> box
| ComboBox a -> a |> box

interface IValueConverter with
member this.Convert
(
value: obj,
targetType: System.Type,
parameter: obj,
culture: System.Globalization.CultureInfo
) : obj =
match value with
| :? list<Components> as components -> components |> List.map toVM |> box
| _ -> failwith "shouldn't happen"

member this.ConvertBack
(
value: obj,
targetType: System.Type,
parameter: obj,
culture: System.Globalization.CultureInfo
) : obj =
raise (System.NotImplementedException())
58 changes: 38 additions & 20 deletions src/Samples/SubModelSelectedItem.Core/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ open Serilog.Extensions.Logging
open Elmish.WPF

(*
[toDos]
• *change all [dynamic bindings] to [static bindings] using an upcoming Elmish.WPF revised static bindings approach*
• [?] make "_VM" for each child (cleaner separation)
• [?] would something other than "SubModelSelectItem" be a better option for safety?
• [?] how to better seperate *specific children fields* within dynamic bindings in "Form_VM.Components"? Just comment? Helpers?
• add: DataTemplateSelector
[toDos]
("#" = issue, "•" = task)
# change all [dynamic bindings] to [static bindings] (using an upcoming Elmish.WPF revised static bindings approach?)
• static bindings: make ViewModels for each Component (also working Intellisense for binding submodel in Xalm)
• [?] would something other than "SubModelSelectItem" be a better option?
# not working: DataTemplateSelector
• add: get focus after adding + selecting FormComponent (Behavior)
• refactor: revise all helpers in Form (some were made quick&dirty)
Expand Down Expand Up @@ -69,12 +71,12 @@ module ComboBoxComponent =

type Model =
{ Id: Guid
Name: string // header of GroupBox containing it
Header: string // Header (of GroupBox containing it)
Items: string list }

let create () =
{ Id = Guid.NewGuid()
Name = FormComponentHelpers.generateName "ComboBox_"
Header = FormComponentHelpers.generateName "ComboBox_"
Items = [ "Item 1"; "Item 2"; "Item 3" ] }

let init () = create ()
Expand All @@ -101,6 +103,10 @@ module Form =
CheckBox_Model: CheckBoxComponent.Model
ComboBox_Model: ComboBoxComponent.Model }

module ModelM =
module TextBox =
let get (m: Model) = m.TextBox_Model

let components_Mock =
[ for _ in 1..3 do
yield TextBox(TextBoxComponent.create ())
Expand All @@ -120,7 +126,7 @@ module Form =
| AddTextBox
| AddCheckBox
| AddComboBox
//• SubMsgs
//• SubModels
| TextBox_Msg of TextBoxComponent.Msg
| CheckBox_Msg of CheckBoxComponent.Msg
| ComboBoxC_Msg of ComboBoxComponent.Msg
Expand All @@ -143,7 +149,7 @@ module Form =
match component_ with
| TextBox a -> a.Text
| CheckBox b -> b.Label
| ComboBox c -> c.Name
| ComboBox c -> c.Header

let isSelected selectedId component_ =
match selectedId, component_ with
Expand All @@ -159,7 +165,7 @@ module Form =
match component_ with
| TextBox a -> TextBox { a with Text = "#New# " + a.Text }
| CheckBox b -> CheckBox { b with Label = "#New# " + b.Label }
| ComboBox c -> ComboBox { c with Name = "#New# " + c.Name }
| ComboBox c -> ComboBox { c with Header = "#New# " + c.Header }

let newComponentWithPrependedName = prependNewName newComponent

Expand Down Expand Up @@ -224,7 +230,7 @@ module Form =
| ComboBoxC_Msg msg -> { m with ComboBox_Model = ComboBoxComponent.update msg m.ComboBox_Model }


//# ViewModel/Bindings
// ViewModel/Bindings
open Form.Form // ugly

[<AllowNullLiteral>]
Expand All @@ -233,27 +239,40 @@ type Form_VM(args) =

new() = Form_VM(Form.init () |> ViewModelArgs.simple)

//• Properties
// I *really* don't like the stringly-typed nature of this binding + no Intellisense in Xaml for submodel properties
//# DataTemplateSelector not working, but SelectedEntity works
//# as ListItem ItemSource = "Elmish.WPF.DynamicViewModel'2"
member _.Components =
base.Get
()
(Binding.subModelSeq (
(fun m -> m.Components),
(fun (e) -> getComponentId e),
(fun () ->
[ "Name"
[
//• TextBox
"Text"
|> Binding.oneWay (fun (_, e) -> getComponentName e)
"SelectedLabel"
|> Binding.oneWay (fun (m, e) ->
if isSelected m.SelectedComponent e then
" - Selected"
else
"") ])

//• CheckBox
// (add later)

//• ComboBox
))


// I don't like the stringly-typed nature of this binding
//# DataTemplateSelector seems to work (though I can't bind to subProperties), but SelectedEntity breaks..
//# as ListItem ItemSource = "ComboBox {Id = 3232 (..) Header = "ComboBox_3232" Items = ["Item 1"; "Item 2"; "Item 3"]}"
member _.Components2 = base.Get() (Binding.oneWaySeq (( _.Components ), (=), id))


// I don't like the stringly-typed nature of this binding either
member _.SelectedEntity
with get () =
base.Get
Expand Down Expand Up @@ -318,9 +337,8 @@ type Form_VM(args) =
| Form.Components.ComboBox cModel -> Some cModel.Id
|> Form.Msg.Select))

member _.Deselect =
base.Get () (Binding.cmd (fun (m: Form.Model) -> Form.Msg.Select None))

member _.Deselect = base.Get() (Binding.CmdT.setAlways (Form.Msg.Select None))


module Program =
let main window =
Expand All @@ -334,4 +352,4 @@ module Program =

WpfProgram.mkSimpleT Form.init Form.update Form_VM
|> WpfProgram.withLogger (new SerilogLoggerFactory(logger))
|> WpfProgram.startElmishLoop window
|> WpfProgram.startElmishLoop window
74 changes: 59 additions & 15 deletions src/Samples/SubModelSelectedItem/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,61 @@
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
<fsWPF:GetComponentsVMToResource
x:Key="GetComponentsVmToResource_Converter" />

<DataTemplate
x:Key="TextBoxTemplate">
<StackPanel
Background="DarkGreen"
Orientation="Horizontal">
<TextBlock
MinWidth="300"
Text="{Binding Text}" />
<TextBlock
FontWeight="DemiBold"
Text="{Binding SelectedLabel}" />
</StackPanel>
</DataTemplate>

<DataTemplate
x:Key="CheckBoxTemplate">
<StackPanel
Background="DarkRed"
Orientation="Horizontal">
<!--<CheckBox
Content="{Binding Label}"
IsChecked="{Binding IsChecked}" />-->
<TextBlock
FontWeight="DemiBold"
Text="{Binding SelectedLabel}" />
</StackPanel>
</DataTemplate>

<DataTemplate
x:Key="ComboBoxTemplate">
<StackPanel
Background="DarkOrange"
Orientation="Horizontal">
<!--<TextBlock
Text="{Binding Header}" />
<ComboBox
Text="{Binding Name}" />-->
<TextBlock
FontWeight="DemiBold"
Text="{Binding}" />
</StackPanel>
</DataTemplate>

<fsWPF:ComponentsTemplateSelector
x:Key="ComponentsTemplateSelector"
CheckBox_DT="{StaticResource CheckBoxTemplate}"
ComboBox_DT="{StaticResource ComboBoxTemplate}"
TextBox_DT="{StaticResource TextBoxTemplate}" />

</Window.Resources>


<StackPanel
Margin="0,15,0,0">
Expand Down Expand Up @@ -62,11 +117,12 @@
</StackPanel>

<ListView
Height="200"
Height="360"
Margin="5"
HorizontalContentAlignment="Center"
ItemsSource="{Binding Components}"
SelectedItem="{Binding SelectedEntity}">
d:SelectedItem="{Binding SelectedEntity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemTemplateSelector="{StaticResource ComponentsTemplateSelector}"
ItemsSource="{Binding Components}">
<ListView.ItemContainerStyle>
<Style
TargetType="ListViewItem">
Expand All @@ -75,18 +131,6 @@
Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel
HorizontalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Text="{Binding Name}" />
<TextBlock
Text="{Binding SelectedLabel}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

<TextBlock
Expand Down

0 comments on commit e4e7720

Please sign in to comment.