XAML中的主要细节 - 通过绑定/命令管理ListView选择,同时允许取消

时间:2013-06-18 17:33:50

标签: wpf xaml mvvm prism mvvm-light

我正在尝试构建一个WPF应用程序,用于遵循最佳MVVM实践,并且我很快发现我不确定最佳实践是什么! :)

我现在有一个特定的问题。

作为一些背景(如果它在我的片段中显示),我使用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;
    }
}

左侧的两列包含一个实体列表,当选择一个实体时,右侧的详细信息列会更新以允许查看/编辑。如果用户在右侧面板中编辑实体,则标记其视图模型&#34;脏&#34;。

当用户尝试在左栏中选择其他实体时,我希望能够(在ViewModel中)询问用户是否要离开并丢失他们的更改,或者他们是否&# 39;我想保存它们。

我可以提供(通过导航服务),但我不知道如何实际取消&#34;取消&#34;在视图模型中工作,让我重新思考我的整个方法。

如果我在两个方向绑定SelectedItem,那么我认为我可能不会在RaisePropertyChanged被触发之前更新基础字段 - 但是因为我需要调用异步代码来保持我的实体(HttpClient)我无法在属性设置器中执行此操作。

所以我已经完成了上述工作,但如果没有感觉像是可怕的黑客,我就无法工作。

有没有更好的通用解决方案,我只是没有看到?或者更好的例子呢?

修改

我意识到我不清楚我想在这里完成什么。问题不在于如何还原所做的更改,因为@Alan正确指出有一些标准方法可以解决这个问题。

我试图在左窗格中尝试更改所选类型时向用户询问以下内容:

您要保存此类型吗?

[是] - 保存并允许导航

[否] - 还原更改并允许导航

[取消] - 保持更改并取消导航

它的[取消]我不知道如何妥善处理。

1 个答案:

答案 0 :(得分:0)

我相信你的答案是在棱镜书中实施IConfirmNavigationRequest?

确认或取消导航

您经常会发现在导航操作期间需要与用户进行交互,以便用户可以确认或取消它。例如,在许多应用中,用户可以在输入或编辑数据的过程中尝试导航。在这些情况下,您可能想要询问用户是否要在继续离开页面之前保存或丢弃已输入的数据,或者用户是否想要完全取消导航操作。 Prism通过IConfirmNavigationRequest接口支持这些场景。

来自棱镜书 8: Navigation