5

ビジネス オブジェクト ( なしAllowNullLiteralAttribute) があるとします。

type Person(name: string) =
    member val Name = name
    override x.ToString() = name

そして、選択された人がオプションで設定されたビューモデル。

type MainWindowModel() =

    let mutable selectedPerson: Person option = None
        :
    member val People = ObservableCollection<Person>()
    member x.SelectedPerson
        with get() = selectedPerson
        and set(v) =
            if selectedPerson <> v then
                selectedPerson <- v
                x.RaisePropertyChanged("SelectedPerson")

SelectedItem(を使用せずに) WPF コントロールのプロパティを F# オプション プロパティにバインドする最良の方法は何AllowNullLiteralAttributeですか?

私がこれをしたら...

<StackPanel>
    <ListBox ItemsSource="{Binding People}"
             SelectedItem="{Binding SelectedPerson}"
             DisplayMemberPath="Name" />
    <TextBlock Text="{Binding SelectedPerson}" />
</StackPanel>

...エラーになります。 「George」を「Person」型から「Microsoft.FSharp.Core.FSharpOption`1[Person]」型に変換できません

4

2 に答える 2

10

私が現在取っているアプローチは、自分で書くことIValueConverterです。

open System
open System.Globalization
open System.Windows.Data

type OptionsTypeConverter() =

    // from http://stackoverflow.com/questions/6289761
    let (|SomeObj|_|) =
      let ty = typedefof<option<_>>
      fun (a:obj) ->
        let aty = a.GetType()
        let v = aty.GetProperty("Value")
        if aty.IsGenericType && aty.GetGenericTypeDefinition() = ty then
          if a = null then None
          else Some(v.GetValue(a, [| |]))
        else None

    interface IValueConverter with

        member x.Convert(value: obj, targetType: Type, parameter: obj, culture: CultureInfo) =
            match value with
            | null -> null
            | SomeObj(v) -> v
            | _ -> value

        member x.ConvertBack(value: obj, targetType: Type, parameter: obj, culture: CultureInfo) =
            match value with
            | null -> None :> obj
            | x -> Activator.CreateInstance(targetType, [| x |])

そして、私の XAML は次のようになります。

<StackPanel>
    <ListBox ItemsSource="{Binding People}"
             SelectedItem="{Binding SelectedPerson, Converter={StaticResource OptionsTypeConverter1}}"
             DisplayMemberPath="Name" />
    <TextBlock Text="{Binding SelectedPerson, Converter={StaticResource OptionsTypeConverter1}}" />
</StackPanel>

もっと簡単な方法があるかもしれません。このコンバーターは、フレームワークに既に存在している場合があります。より良い実装があるかもしれません。

于 2013-07-09T19:38:14.573 に答える
3

IValueConverterおそらく an を使用するのが最もクリーンなアプローチだと思います。

別の方法として、オプション タイプにメンバーがあるという事実を使用することもできますValue(これは の値を返すか、Someまたは の例外をスローしますNone)。したがって、値が常に存在することがわかっている場合、または例外が何も壊さない場合 (試したことはありません)、次のように記述できる可能性があります。

<ListBox ItemsSource="{Binding People}"
         SelectedItem="{Binding SelectedPerson.Value}"
         DisplayMemberPath="Name" />

例外が問題である場合、この過去の SO の質問では、次を使用することをお勧めしますPriorityBinding

<ListBox ItemsSource="{Binding People}" DisplayMemberPath="Name">
  <ListBox.SelectedItem>
    <PriorityBinding>
        <Binding Path="SelectedPerson.Value" />
        <Binding Source="{x:Null}" />  <!-- or some other default... -->
    </PriorityBinding>
  </ListBox.SelectedItem>
</ListBox>
于 2013-07-09T20:04:04.957 に答える