在我的previous question中,我問如何使用WPF和MVVM創建一個可關閉的對話框,用於在F#中添加新的Person記錄。現在我的下一步是製作另一個對話框來編輯這些記錄。但我還沒有制定出如何將現有記錄傳遞給ViewModel並使用它填充對話框的字段。我得到異常,因爲F#記錄是不可變的,而ViewModel似乎期望一個可變對象。使用WPF和MVVM編輯F#記錄
我會告訴你我現有的添加對話框的代碼 - 假設編輯對話框看起來是一樣的。
這就是人的記錄:
type Person = { Name: string; Email: string }
下面是添加對話框中的XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fsxaml="http://github.com/fsprojects/FsXaml"
xmlns:local="clr-namespace:ViewModels;assembly=Test3"
local:DialogCloser.DialogResult="{Binding DialogResult}"
Title="Add Person" Height="150" Width="210" ResizeMode="NoResize" >
<Window.DataContext>
<local:PersonAddVM />
</Window.DataContext>
<StackPanel>
<Grid FocusManager.FocusedElement="{Binding ElementName=_name}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Label Content="_Name" Target="_name" Grid.Row="0" Grid.Column="0" Margin="2" />
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" x:Name="_name"
Grid.Row="0" Grid.Column="1" Margin="4" />
<Label Content="_Email" Target="_email" Grid.Row="2" Grid.Column="0" Margin="2" HorizontalAlignment="Left" />
<TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" x:Name="_email"
Grid.Row="1" Grid.Column="1" Margin="4" />
</Grid>
<UniformGrid Rows="1" Columns="2" VerticalAlignment="Center" Margin="2,20,2,2" >
<Button Content="OK" IsDefault="True" IsEnabled="{Binding IsValid}" Command="{Binding OkCmd}"
HorizontalAlignment="Right" Margin="6,0" Width="50" />
<Button Content="Cancel" IsCancel="True" HorizontalAlignment="Left" Margin="6,0" Width="50" />
</UniformGrid>
</StackPanel>
</Window>
這是它(簡體)視圖模型:
type PersonAddVM() as self =
inherit DialogVMBase() // ViewModelBase with a DialogResult property
let name = self.Factory.Backing(<@ self.Name @>, "", hasLengthAtLeast 4)
let email = self.Factory.Backing(<@ self.Email @>, "", hasLengthAtLeast 5)
let makePerson() = { Name = name.Value; Email = email.Value }
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.OkCmd = self.Factory.CommandSync(fun() ->
PersonCache.Add (makePerson()) // PersonCache is based on an Observable Dictionary
self.DialogResult <- true)
和附加從PersonList對話框中打開對話框,該對話框列出所有人並具有此ViewModel代碼:
type PersonListView = XAML<"PersonListView.xaml">
type PersonAddView = XAML<"PersonAddView.xaml">
module PersonViewHandling =
let OpenList() = DialogHelper.OpenDialog (PersonListView())
let OpenAdd() = DialogHelper.OpenDialog (PersonAddView()) // Calls ShowDialog on the view and handles the result
type PersonListVM() as self =
inherit DialogVMBase()
// I want to use the next 3 lines to access the Person selected in the list,
// to pass it to the Edit dialog
let emptyPerson = { Name = ""; Email = "" }
let selectedPerson = self.Factory.Backing(<@ self.SelectedPerson @>, emptyPerson)
member self.SelectedPerson with get() = selectedPerson.Value and set value = selectedPerson.Value <- value
member self.AddCmd = self.Factory.CommandSync (fun _ -> PersonViewHandling.OpenAdd() |> ignore)
那麼我怎樣才能使用這種方法(或類似的)打開一個相同的編輯對話框,並使用SelectedPerson填充其字段?
聽起來你已經有了'PersonAddVM'類的正確方法:創建一個具有可變字段的類,然後將它傳遞給WPF,以便按照它認爲合適的方式進行變異。然後,一旦你知道WPF已經完成了對你的類的變異並且它的字段包含了最終值(例如,當用戶在對話框上點擊OK),你就可以使用'makePerson'這樣的函數從當前值創建一個F#記錄字段,並在代碼的其餘部分使用該不可變記錄。 – rmunn