WPF中具有丰富单元格内容的多列列表
我正在尝试使用WPF和F#编写一个自动化测试工具。我希望将聚合测试结果显示为多列列表中的行。理想情况下,我希望在每个单元格中显示丰富的内容,例如使用颜色突出显示特定测试的问题,或通过工具提示提供详细信息。但是,我不知道如何将比普通字符串更丰富的内容放入多列WPF中具有丰富单元格内容的多列列表,wpf,f#,Wpf,F#,我正在尝试使用WPF和F#编写一个自动化测试工具。我希望将聚合测试结果显示为多列列表中的行。理想情况下,我希望在每个单元格中显示丰富的内容,例如使用颜色突出显示特定测试的问题,或通过工具提示提供详细信息。但是,我不知道如何将比普通字符串更丰富的内容放入多列ListView 此外,我不喜欢XAML或数据绑定,更喜欢编写普通的F#代码。我能编写的显示多列WPFListView的最简单程序是: open System.Windows let gridView = Controls.GridView(
ListView
此外,我不喜欢XAML或数据绑定,更喜欢编写普通的F#代码。我能编写的显示多列WPFListView
的最简单程序是:
open System.Windows
let gridView = Controls.GridView()
let listView = Controls.ListView(View=gridView)
type SystemParams = { Name: string; Value: obj }
[<System.STAThread>]
do
let column header binding =
let binding = Data.Binding binding
Controls.GridViewColumn(Header=header, DisplayMemberBinding=binding)
for header, binding in ["Name", "Name"; "Value", "Value"] do
column header binding
|> gridView.Columns.Add
for prop in typeof<SystemParameters>.GetProperties() do
if prop.PropertyType <> typeof<ResourceKey> then
{ Name = prop.Name; Value = prop.GetValue(null, null) }
|> listView.Items.Add
|> ignore
Application().Run(Window(Content=listView)) |> ignore
是的,这是可能的,但有点棘手,但一旦你掌握了方法,它就相当灵活了。WFP有一个灵活的模板系统,它可以通过代码和XAML实现,除了在代码中实现这一点的例子要少得多 它主要涉及如何使用
FrameworkElementFactory
覆盖列表框默认模板并显示所需的UI元素。然后使用Binding
类指定控件应如何绑定到数据
我用WPF和F#编写了一个twitter客户端,并使用这种方法在列表框中显示tweet的列。看看createTweetContainerTemplate
函数是如何工作的。
然后,除非您真的需要对列表框中的每一行的布局进行高度控制,否则使用datagrid可能更简单。我制作了一个简单的combinator库来通过代码构建WPF UI,我在我的pit项目中使用此模式来创建HTML元素 命名空间FSharp.WPF 开放系统 开放系统 打开System.Windows.Controls
[<AutoOpen>]
module Combinator =
type XDef =
| Attr of string * obj
| Tag of Type * XDef list
//| Element of FrameworkElement
[<AutoOpen>]
module Operators =
let (@=) (p:string) (v:obj) : XDef = Attr(p,v)
module internal Helpers =
let createEl (ty:Type) = new FrameworkElementFactory(ty)
let tag name attr = Tag(name,attr)
//let el dom = Element(dom)
let rec build (tag:XDef) =
match tag with
| Tag(ty,defs) ->
let attrs = defs |> List.choose(fun t -> match t with | Attr(k,v) -> Some(k,v) | _ -> None)
let tags = defs |> List.choose(fun t -> match t with | Tag(k,v) -> Some(t) | _ -> None)
/// create the element and set attributes
let el = Helpers.createEl(ty)
let rec setProps (d:(string*obj) list) =
match d with
| [] -> ()
| (p,v) :: t ->
let dp = System.ComponentModel.DependencyPropertyDescriptor.FromName(p, el.Type,el.Type)
el.SetValue(dp.DependencyProperty,v)
setProps attrs
let rec gen (d:XDef list) =
match d with
| [] -> ()
| h::t ->
let childEl = build(h)
el.AppendChild(childEl)
gen(t)
gen tags
el
//| Element(el) -> el
| Attr(key,value) -> failwith "Unrecognized sequence"
let make xdef =
let fEl = build xdef
let contentEl = new ContentControl()
contentEl.ContentTemplate <- new DataTemplate(VisualTree=fEl)
contentEl :> FrameworkElement
let create() =
tag typeof<System.Windows.Controls.Button> ["Content"@="Hello World"]
|> Combinator.make
let create2() =
tag typeof<StackPanel> [
tag typeof<Button> ["Content"@="Button 1"]
tag typeof<Button> ["Content"@="Button 2"]
]
|> Combinator.make
[<STAThread>]
[<EntryPoint>]
let main(_) =
let el = Test.create2() // Test.create1()
let window = new Window(Content = el, Height = 600.0, Width = 800.0, Title = "WpfApplication1")
let app = new Application()
app.Run(window)
[]
模组合器=
XDef型=
|字符串*对象的属性
|类型为*XDef列表的标记
//|框架元素
[]
模运算符=
let(@=)(p:string)(v:obj):XDef=Attr(p,v)
模块内部助理=
让createEl(ty:Type)=新FrameworkElementFactory(ty)
让标记名attr=tag(名称,attr)
//设el dom=元素(dom)
让rec生成(标记:XDef)=
匹配标签
|标签(ty,defs)->
让attrs=defs |>列表。选择(乐趣t->将t与| Attr(k,v)->一些(k,v)|->无)
让tags=defs |>列表。选择(乐趣t->将t与| Tag(k,v)->一些(t)|->无)
///创建元素并设置属性
let el=Helpers.createEl(ty)
let rec setProps(d:(字符串*obj)列表)=
匹配
| [] -> ()
|(p,v)::t->
设dp=System.ComponentModel.DependencyPropertyDescriptor.FromName(p,el.Type,el.Type)
el.设定值(dp.DependencyProperty,v)
setProps属性
let rec gen(d:XDef列表)=
匹配
| [] -> ()
|h::t->
let childEl=构建(h)
el.AppendChild(儿童)
总务(t)
gen标签
埃尔
//|元素(el)->el
|Attr(键,值)->故障与“无法识别的序列”
让我们制作xdef=
设fEl=buildxdef
让contentEl=newcontentcontrol()
contentEl.ContentTemplate框架元素
它现在非常低调,只需要创建对象,但它可以扩展到更多的数据绑定和其他事情,并且一些类型检查应该可以发现对象创建中的错误
用法:
模块测试=
打开System.Windows.Controls
[<AutoOpen>]
module Combinator =
type XDef =
| Attr of string * obj
| Tag of Type * XDef list
//| Element of FrameworkElement
[<AutoOpen>]
module Operators =
let (@=) (p:string) (v:obj) : XDef = Attr(p,v)
module internal Helpers =
let createEl (ty:Type) = new FrameworkElementFactory(ty)
let tag name attr = Tag(name,attr)
//let el dom = Element(dom)
let rec build (tag:XDef) =
match tag with
| Tag(ty,defs) ->
let attrs = defs |> List.choose(fun t -> match t with | Attr(k,v) -> Some(k,v) | _ -> None)
let tags = defs |> List.choose(fun t -> match t with | Tag(k,v) -> Some(t) | _ -> None)
/// create the element and set attributes
let el = Helpers.createEl(ty)
let rec setProps (d:(string*obj) list) =
match d with
| [] -> ()
| (p,v) :: t ->
let dp = System.ComponentModel.DependencyPropertyDescriptor.FromName(p, el.Type,el.Type)
el.SetValue(dp.DependencyProperty,v)
setProps attrs
let rec gen (d:XDef list) =
match d with
| [] -> ()
| h::t ->
let childEl = build(h)
el.AppendChild(childEl)
gen(t)
gen tags
el
//| Element(el) -> el
| Attr(key,value) -> failwith "Unrecognized sequence"
let make xdef =
let fEl = build xdef
let contentEl = new ContentControl()
contentEl.ContentTemplate <- new DataTemplate(VisualTree=fEl)
contentEl :> FrameworkElement
let create() =
tag typeof<System.Windows.Controls.Button> ["Content"@="Hello World"]
|> Combinator.make
let create2() =
tag typeof<StackPanel> [
tag typeof<Button> ["Content"@="Button 1"]
tag typeof<Button> ["Content"@="Button 2"]
]
|> Combinator.make
[<STAThread>]
[<EntryPoint>]
let main(_) =
let el = Test.create2() // Test.create1()
let window = new Window(Content = el, Height = 600.0, Width = 800.0, Title = "WpfApplication1")
let app = new Application()
app.Run(window)
let create()=
标签类型[“Content”@=“Hello World”]
|>组合器
让我们创建2()=
标签类型[
标签类型[“内容”@=“按钮1”]
标签类型[“内容”@=“按钮2”]
]
|>组合器
[]
[]
let main(u)=
设el=Test.create2()//Test.create1()
let window=新窗口(内容=el,高度=600.0,宽度=800.0,Title=“WpfApplication1”)
let app=新应用程序()
应用程序运行(窗口)
正如您所看到的,嵌套元素意味着面板元素,但可能有一些额外的杠杆作用,允许类型识别面板元素或内容元素。但你知道,这可能是有用的。你觉得怎么样
-Fahad通过使用基于索引的绑定而不是成员名,可以避免复制字段名的特定问题。请参见此处对示例所做的更改:
开放系统
开放系统
让gridView=Controls.gridView()
让listView=Controls.listView(View=gridView)
[]
做
让列索引标题=
let binding=Data.binding(sprintf“[%d]”索引)
Controls.GridViewColumn(标题=标题,DisplayMemberBinding=绑定)
[“名称”;“值”]
|>List.mapi列
|>List.iter gridView.Columns.Add
对于typeof.GetProperties()中的prop
如果prop.PropertyType类型为,则
([| prop.Name;prop.GetValue(null,null)|]:对象数组)
|>listView.Items.Add
|>忽略
Application().Run(Window(Content=listView))|>ignore
关于为ListView
提供一系列控件,其级别略低于ListView
ListView
和DataGrid
都假设您有一些大致相同的对象集合,希望显示这些对象(通常为行),并且对这些对象的信息(列定义)有一些概念。这两个控件在这种情况下都会有所帮助,尽管我同意它们的一般假设,即您希望对类型的成员使用反射,这可能会很烦人
如果您希望能够指定任何控件的网格,那么正如您所提到的,网格
面板布局可能更合适。您还说了