【问题标题】:F# how to set content on WPF Label programmaticallyF#如何以编程方式在WPF标签上设置内容
【发布时间】:2014-09-16 13:15:56
【问题描述】:

F# 代码

open System
open System.Windows
open System.Windows.Controls

let resourceLocator = new Uri("/ConsoleApplication3;component/MainWindow.xaml", UriKind.Relative)

let lbl2 = (Application.LoadComponent(resourceLocator) :?> Window).FindName("lbl") :?> Label

let tb = (Application.LoadComponent(resourceLocator) :?> Window).FindName("tb") :?> TextBlock

let tbo = (Application.LoadComponent(resourceLocator) :?> Window).FindName("tbo") :?> TextBox

let value = "ROCK!"
let clickButton = fun _ -> 
    lbl2.Content <- "ROCK!"

let loadWindow() = 
    let resourceLocator = new Uri("/ConsoleApplication3;component/MainWindow.xaml", UriKind.Relative)
    let window = Application.LoadComponent(resourceLocator) :?> Window
    (window.FindName("clickButton") :?> Button).Click.Add(clickButton)
    window

[<STAThread>]
(new Application()).Run(loadWindow()) |> ignore

我的 Xaml WPF 代码:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="500">
    <Grid>
        <Button Name="clickButton" Content="Click  me!" Height="40" Width="150" />
        <Label Name="lbl" Content="Label" HorizontalAlignment="Left" Margin="198,40,0,0" VerticalAlignment="Top"/>
        <TextBlock Name="tb" HorizontalAlignment="Left" Margin="198,201,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
        <TextBox Name="tbo" HorizontalAlignment="Left" Height="23" Margin="340,198,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
    </Grid>
</Window>

我打算通过单击按钮更改 Label:lbl 的内容,但由于某种原因它不起作用,但看不出原因

【问题讨论】:

  • 你有什么异常吗?
  • 附带说明,我强烈建议使用 FsXaml 而不是手动执行此操作 - 它让生活变得更加轻松。 github.com/fsprojects/FsXaml
  • 这可能是因为控件的内容不是string,而是一个控件。在 XAML 中,它会将文本解析为您的控件,但是当您从后面的代码中设置它时,您需要将内容设置为某种控件。
  • @DLeh 不,您可以将Content 设置为任何值。它以 xaml 的形式在后面的代码中运行 smae:msdn.microsoft.com/en-us/library/… 字符串的默认 DataTemplate 会将其转换为 TextBlock
  • 好吧,也许它与 F# 的功能不同。我以为我在将内容设置为 C# 代码隐藏中的字符串时遇到了问题。

标签: wpf f#


【解决方案1】:

在这种情况下,问题在于您多次加载组件。当您调用clickButton 时,它使用的是绑定到与主实例分开的已加载窗口实例的绑定值的结果。

您应该能够解决这个问题,在这种情况下,通过使用 Application.Current.MainWindow 来获取已经显示的窗口:

open System
open System.Windows
open System.Windows.Controls

let resourceLocator = new Uri("/ConsoleApplication3;component/MainWindow.xaml", UriKind.Relative)

// This needs to be a function, so it's not evaluated before the window is created
let getLbl2 () = Application.Current.MainWindow.FindName("lbl") :?> Label

let value = "ROCK!"
let clickButton = fun _ -> 
    let lbl = getLbl2()
    lbl.Content <- "ROCK!"

let loadWindow() = 
    let resourceLocator = new Uri("/ConsoleApplication3;component/MainWindow.xaml", UriKind.Relative)
    let window = Application.LoadComponent(resourceLocator) :?> Window
    (window.FindName("clickButton") :?> Button).Click.Add(clickButton)
    window

[<STAThread>]
(new Application()).Run(loadWindow()) |> ignore

话虽如此,我真的建议使用FsXaml 来处理您的 WPF 资源。类型提供程序将为您提供对数据的安全访问,让生活变得更加简单。

这可以使用 FsXaml 重写为:

open System
open System.Windows
open System.Windows.Controls
open FsXaml

type MainWindow = XAML<"MainWindow.xaml">

let loadWindow() = 
    let window = MainWindow().CreateRoot()
    let accessor = MainWindow.Accessor window
    accessor.clickButton.Click.Add(fun _ -> accessor.lbl.Content <- "ROCK!")
    window

[<STAThread>]
(new Application()).Run(loadWindow()) |> ignore

请注意,当使用FsXaml 时,您可以获得成员的完全智能感知,并且不再需要魔法字符串。

【讨论】:

  • 谢谢,您的代码不太好用,但是在 Application 之后添加了 .Current 并感谢您提供有关 FsXaml 的提示,我一定会调查的。
  • @user3874490 在其中添加了 .Current - 这就是您有时直接输入答案时会发生的情况 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多