首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将WPF控件绑定到F#选项

将WPF控件绑定到F#选项
EN

Stack Overflow用户
提问于 2013-07-09 19:38:14
回答 2查看 921关注 0票数 5

假设我有一个业务对象(没有AllowNullLiteralAttribute)。

代码语言:javascript
复制
type Person(name: string) =
    member val Name = name
    override x.ToString() = name

和视图模型,所选的人可选地设置。

代码语言:javascript
复制
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")

将WPF控件的SelectedItem属性绑定到F#选项属性(不使用AllowNullLiteralAttribute)的最佳方法是什么?

如果我这么做..。

代码语言:javascript
复制
<StackPanel>
    <ListBox ItemsSource="{Binding People}"
             SelectedItem="{Binding SelectedPerson}"
             DisplayMemberPath="Name" />
    <TextBlock Text="{Binding SelectedPerson}" />
</StackPanel>

...it导致错误,无法将“George”从“Person”类型转换为“Microsoft.FSharp.Core.FSharpOption`1Person”

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-09 19:38:14

我目前采用的方法是编写自己的IValueConverter

代码语言:javascript
复制
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看起来是这样的

代码语言:javascript
复制
<StackPanel>
    <ListBox ItemsSource="{Binding People}"
             SelectedItem="{Binding SelectedPerson, Converter={StaticResource OptionsTypeConverter1}}"
             DisplayMemberPath="Name" />
    <TextBlock Text="{Binding SelectedPerson, Converter={StaticResource OptionsTypeConverter1}}" />
</StackPanel>

也许还有更简单的方法。此转换器可能已经存在于框架中。可能有更好的实现。

票数 10
EN

Stack Overflow用户

发布于 2013-07-09 20:04:04

我认为使用IValueConverter可能是最干净的方法。

或者,您可以使用选项类型具有Value成员的事实(该成员返回Some的值或为None抛出异常)。因此,如果您知道总是有一个值,或者如果异常没有破坏任何东西(我没有尝试过),那么您可以编写:

代码语言:javascript
复制
<ListBox ItemsSource="{Binding People}"
         SelectedItem="{Binding SelectedPerson.Value}"
         DisplayMemberPath="Name" />

如果异常有问题,则this past SO question suggests使用PriorityBinding

代码语言:javascript
复制
<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>
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17556710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档