我正在尝试构建一个遵循最佳 MVVM 实践的 WPF 应用程序进行演示,但我很快发现我不确定最佳实践是什么!:)
我现在有一个具体问题。
作为一些背景(如果它显示在我的片段中),我使用 MVVMLight(因为它的 PCL 可移植性),NInject 作为容器,使用 Prism 作为其区域支持。
看法
[片段]
<!-- bind the selection of a new item to the view model -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectTypeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!-- visual template of the list items -->
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock>Name: <Run Text="{Binding Name}"></Run></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- detail view -->
<Grid Grid.Row="0" Grid.Column="1">
<StackPanel Orientation="Vertical" Margin="5">
<Label>ID</Label>
<TextBox Text="{Binding SelectedType.Id, Mode=TwoWay}" IsEnabled="False"></TextBox>
<Label>Name</Label>
<TextBox Text="{Binding SelectedType.Name, Mode=TwoWay}"></TextBox>
</StackPanel>
</Grid>
视图模型
[片段]
public class ClientTypesViewModel : BaseUpdateableViewModel
{
private ThingType selectedtype = null;
public ThingType SelectedType
{
get { return selectedtype; }
protected set { Set(() => SelectedType, ref selectedtype, value); }
}
private RelayCommand<ThingType> selecttypecommand;
public RelayCommand<ThingType> SelectTypeCommand
{
get { return selecttypecommand ?? (selecttypecommand = new RelayCommand<ThingType>(ExecuteSelectTypeCommand)); }
}
private async void ExecuteSelectTypeCommand(ThingType newtype)
{
// Save the type if required - goes away to a service (HttpClient...)
if (!await SaveSelectedType())
{
// Cancel navigation?
return;
}
// Update the selected type
this.SelectedType = newtype;
}
private async Task<bool> SaveSelectedType()
{
if (selectedtype == null) return true;
if (!selectedtype.IsDirty) return true;
bool? result = await navigationservice.AskConfirmation("Do you want to save this client type?", "Yes", "No", "Cancel");
if (result == null)
return false; // cancel
if (!result.Value)
{
selectedtype.MakeClean();
return true; // ignore changes
}
// Ask the data service to save for us
await dataservice.UpdateClientType(selectedtype);
selectedtype.MakeClean();
return true;
}
}
Two columns, left hand holds a list of entities that when one is selected, the details column on the right updates to allow view/edit. 如果用户在右侧面板中编辑了实体,我将其视图模型标记为“脏”。
当用户尝试在左栏中选择不同的实体时,我希望能够(在 ViewModel 中)询问用户是否要离开并丢失更改,或者是否要保存更改.
这我可以呈现(通过导航服务),但我不知道如何在视图模型中真正使“取消”工作,这让我重新思考我的整个方法。
如果我在两个方向上绑定,SelectedItem
那么我认为我不能在RaisePropertyChanged
触发之前更新基础字段 - 但是因为我需要调用异步代码来持久化我的实体(HttpClient),所以我不能在属性设置器。
所以我已经完成了上述操作,如果没有可怕的黑客攻击,我就无法真正开始工作。
有没有更好的通用解决方案,我只是没有看到?或者更好的例子?
编辑
我已经意识到我不清楚我在这里想要完成什么。问题不在于如何恢复所做的更改,正如@Alan 正确指出的那样,有一些标准的方法可以解决这个问题。
我在尝试更改左窗格中的选定类型时向用户询问以下内容:
您要保存此类型吗?
[是] - 保存并允许导航
[否] - 还原更改并允许导航
[取消] - 保留更改并取消导航
它的[取消]我不知道如何正确处理。