如何在主/详细信息方案中保留对详细信息的更改

时间:2014-06-20 08:11:36

标签: wpf mvvm asp.net-web-api

我觉得这应该很简单,但我是WPF和MVVM的新手,并且无法弄清楚使用MVVM在哪里做到这一点。我已经四处搜索了wpf + master + detail + mvvm,但我发现的所有示例都没有将数据保存回数据库/ webservice,这正是我试图完成的。

我应该在MVVM中使用HttpClient将我的调用放在哪里?我想在用户更改TodoModel的Text属性时调用Web API,例如PUT http://webapi.example.com/todos/5请求正文{ "Text":"This text is updated" }

型号:

public class TodoModel
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Text { get; set; }
}

查看:

<Window x:Class="TodoMvvm.TodoView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TodoMvvm"
        Title="TodoView" Height="350" Width="525">
    <Window.DataContext>
        <local:TodoViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <ListBox Grid.Column="0" x:Name="TodoListBox" ItemsSource="{Binding Todos}" DisplayMemberPath="Title" SelectedItem="{Binding Path=SelectedTodo}" />
        <TextBox Grid.Column="1" x:Name="TodoTextBox" Text="{Binding Path=SelectedTodo.Text, UpdateSourceTrigger=PropertyChanged}"  />
    </Grid>
</Window>

视图模型:

public class TodoViewModel : INotifyPropertyChanged
{
    public ObservableCollection<TodoModel> Todos { get; set; }

    private TodoModel _selectedTodo;
    public TodoModel SelectedTodo 
    {
        get 
        { 
            // This triggers when changing the todo text, but it feels wrong to post changes back to the web api in a getter?!
            return _selectedTodo; 
        }
        set 
        { 
            _selectedTodo = value; 
            RaisePropertyChanged("SelectedTodo"); 
        }
    }

    private ObservableCollection<TodoModel> GetTodoModels()
    {
        // Todo models should be retrieved from a web api.
        var todos = new ObservableCollection<TodoModel>();
        todos.Add(new TodoModel { Id = 1, Title = "Lorem", Text = "Lorem ipsum dolor sit amet" });
        todos.Add(new TodoModel { Id = 2, Title = "Consectetur", Text = "Consectetur adipisicing elit" });
        todos.Add(new TodoModel { Id = 3, Title = "Sed", Text = "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua" });

        return todos;
    }

    public TodoViewModel()
    {
        Todos = GetTodoModels();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

2 个答案:

答案 0 :(得分:0)

  

这不是试图回答这个问题,而是试图向提问者解释他们的问题不属于本网站的主题。

你让WPF与数据持久性混淆......两者完全无关。

  

Windows Presentation Foundation(WPF)是下一代演示系统,用于构建具有视觉震撼用户体验的Windows客户端应用程序。

另一方面:

  

持久数据结构是一种数据结构,在修改时始终保留自身的先前版本

在我看来,好像你在问如何保存分层数据,在这种情况下,WPF与这个问题完全无关。

这就是如何保存我的分层数据的主题?在我看来,这个网站上的问题范围太广了,因为有很多方法可以保存数据。要继续这个问题,您需要询问一个可以实际回答的特定编程相关问题。


更新&gt;&gt;&gt;

现在我们知道你想知道在哪里放置数据访问代码,我可以继续。但是,您会注意到MVVM中没有DA(用于数据访问)。 MVVM是一种开发方法或架构模式,它没有规定任何特定的数据访问方法。

说到这一点,从更标准的开发角度来看,习惯上将数据访问层与UI层(MVVM中的V),业务数据模型层(MVVM中的M)和业务逻辑分开(您在MVVM中的VM)。这种分离可能是在小型应用程序中使用文件夹,或在较大的应用程序中使用项目。这称为separation of concerns


最终更新&gt;&gt;&gt;

你把代码放在哪里完全取决于你。如前所述,MVVM中没有规则指定您必须访问数据的位置,无论是来自Web服务,数据库还是硬盘驱动器上的简单文本文件。

显然,数据必须在某个阶段通过视图模型,因此在WPF应用程序中找到Web服务代码的两个最有可能的地方是

a)直接在视图模型中,或者
b)在视图模型引用的服务类中。

然而,由于这只是我的意见,而其他人会有不同的意见,所以对你的问题没有一个正确答案。这就是为什么这些类型的主观问题被认为是Stack Overflow的主题。

答案 1 :(得分:0)

我想您现在已经解决了您的问题,但是为了帮助以后可能会遇到的其他人,我会给您一个机会。有很多方法可以解决此问题(当然)。

在所有情况下,出于多种原因,您可能应该将数据的获取和持久化代码放入一个类(或facad模式,接口或类似的东西)中。

您可以将“保存”按钮放在某处。我只是说这是一个选择...:)

简单问题的简单解决方案。 基本问题是您的“详细视图”太直接绑定到母版了。对于这个简单的示例,您说“感觉不对劲”的解决方案可能是最好的,因为任何其他解决方案都会增加可能没有用的复杂性。在一个非常简单的应用程序中,我认为可以忍受一些代码味道。如果我要在树林里远足一个小时,那么没人会在乎我是否穿上了肮脏,有臭味的长筒袜。我不想在这次短途徒步旅行之前洗一下它们。

更复杂的解决方案。 我正在使用TreeView(主视图)和DetailViewer(详细信息)显示一个项目,该项目根据在TreeView中选择的项目的数据类型显示不同的UserControl。不是将DetailViewer直接绑定到TreeView,而是将TreeView绑定到ViewModel(tvVM)。并且TreeView中的每个项目都绑定到一个项目ViewModel(itemVM)。当所选择的项目在TreeView改变DetailViewer绑定到itemVM。因此,最终所有内容都绑定到ViewModel而不是直接绑定到Model。

现在。在某些时候,您将需要代码来更改要显示的详细数据(再次,而不是直接绑定)。我使用在itemVM上IsSelected属性更改时触发的事件处理程序。然后,我只是异步地保留数据。 Here是一篇介绍如何执行此操作的文章。

另一种选择是要等到应用关闭或其他有用事件来保存数据。在许多情况下,这可能不切实际。