首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用FSharp.ViewModule关闭对话框

用FSharp.ViewModule关闭对话框
EN

Stack Overflow用户
提问于 2016-12-06 08:41:45
回答 1查看 295关注 0票数 5

在前面的问题“使用FSharp.ViewModule启用对话框OK按钮”中,只有当对话框字段的验证器为真,并且ViewModule的IsValid属性变为真时,才启用对话框的OK按钮。但在那之后我又遇到了一些问题:

1)单击OK按钮没有关闭对话框,即使我在XAML中设置了IsDefault="true"

2)当单击“确定”按钮时,有时我希望执行比ViewModule验证器提供的更多的检查(例如,检查电子邮件地址)。然后,如果此自定义验证失败,我希望停止对话框关闭。

但在使用F#和MVVM时,我不知道如何做到这两种方法。首先,我尝试将XAML放入C#项目中,并将视图模型代码放入F#库中。然后,我在后面的代码中使用OK按钮的Click处理程序来关闭窗口。这是固定的,但不是2)。

这是我的XAML:

代码语言:javascript
复制
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="OK" IsEnabled="{Binding IsValid}" IsDefault="true" Command="{Binding OkCommand}" 
    <!--Click="OnOK"--> />

我的视图模型--在validate函数中添加一个注释,以显示单击OK按钮时我想要做的事情:

代码语言:javascript
复制
let name = self.Factory.Backing( <@ self.Name @>, "", notNullOrWhitespace)
let email = self.Factory.Backing( <@ self.Email @>, "", notNullOrWhitespace)
let dialogResult = self.Factory.Backing( <@ self.DialogResult @>, false )

let isValidEmail (e:string) = e.Length >= 5

member self.Name 
    with get() = name.Value 
    and set value = name.Value <- value
member self.Email 
    with get() = email.Value 
    and set value = email.Value <- value
member self.DialogResult
    with get() = dialogResult.Value
    and set value = dialogResult.Value <- value

member self.OkCommand = self.Factory.CommandSync(fun () ->
                        if not <| isValidEmail(email.Value) then
                            MessageBox.Show("Invalid Email") |> ignore
                        else
                            dialogResult.Value <- true
                        )
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-06 16:56:45

值得指出的是,MVVM和代码隐藏并不是最好的朋友。

您所指的C#事件处理程序位于Window的代码隐藏文件(即部分类)中。尽管代码隐藏对于视图相关的逻辑被认为是正常的,但MVVM纯粹主义者对它不屑一顾。因此,与在XAML中指定事件处理程序不同,MVVM更喜欢使用Commands

选项A-在代码隐藏中执行,是务实的.

请注意,FsXaml没有提供事件的直接连接(在XAML中指定处理程序),但是您可以自己在代码隐藏中连接事件。

在XAML中命名控件之后,可以在相应的源文件中对其进行保留。

UserDialog.xaml

代码语言:javascript
复制
<Button x:Name="butt" ... >

UserDialog.xaml.fs

代码语言:javascript
复制
namespace Views

open FsXaml

type UserDialogBase = XAML<"UserDialog.xaml">

type UserDialog() as dlg =
    inherit UserDialogBase()

    do dlg.butt.Click.Add( fun _ -> dlg.DialogResult <- System.Nullable(true) )

验证最好在ViewModel中处理,例如,对电子邮件入口使用自定义验证:

https://stackoverflow.com/a/33260010.选项B-您可以使用来遵循模式

首先在解决方案顶部添加一个新的源文件(解决方案资源管理器)

DialogCloser.fs

代码语言:javascript
复制
namespace Views

open System.Windows

type DialogCloser() =    
    static let dialogResultProperty =
        DependencyProperty.RegisterAttached("DialogResult", 
            typeof<bool>, typeof<DialogCloser>, 
                new PropertyMetadata(DialogCloser.DialogResultChanged))

    static member SetDialogResult (a:DependencyObject) (value:string) = 
        a.SetValue(dialogResultProperty, value)

    static member DialogResultChanged 
        (a:DependencyObject) (e:DependencyPropertyChangedEventArgs) =
        match a with
        | :? Window as window
            -> window.DialogResult <- System.Nullable (e.NewValue :?> bool)
        | _ -> failwith "Not a Window"

假设我们的解决方案名为WpfApp (在XAML头中引用),那么我们就可以像这样实现DialogCloser

UserDialog.xaml

代码语言:javascript
复制
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:views="clr-namespace:Views;assembly=WpfApp"
    xmlns:fsxaml="http://github.com/fsprojects/FsXaml"
    views:DialogCloser.DialogResult="{Binding DialogResult}"
    >

        ...

</Window>

现在,在UserDialog的ViewModel中,您可以通过将dialogResult设置为true来连接Command并关闭对话框。

代码语言:javascript
复制
member __.OkCommand = __.Factory.CommandSync(fun () ->
                         if not <| isValidEmail(email.Value) then
                             System.Windows.MessageBox.Show ("...") |> ignore                       
                         else 
                             // do stuff (e.g. saving data)

                             ...

                             // Terminator
                             dialogResult.Value <- true 
                         )

您还可以跳过if / You子句,并使用自定义验证验证电子邮件。

要结束它,您可以使用这个助手函数从MainViewModel调用对话框:

UserDialog.xaml.fs

代码语言:javascript
复制
namespace Views

open FsXaml

type UserDialog = XAML<"UserDialog.xaml">

module UserDialogHandling =    
    /// Show dialog and return result
    let getResult() = 
        let win = UserDialog()
        match win.ShowDialog() with
        | nullable when nullable.HasValue
            -> nullable.Value
        | _ -> false

请注意,在本例中没有“代码隐藏”(在UserDialog类型声明中没有代码)。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40991100

复制
相关文章

相似问题

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