【问题标题】:How to persist changes to details in a master/detail scenario如何在主/细节场景中持久化对细节的更改
【发布时间】:2014-06-20 08:11:35
【问题描述】:

我觉得这应该很简单,但我是 WPF 和 MVVM 的新手,只是不知道在哪里使用 MVVM。我搜索了 wpf+master+detail+mvvm,但我发现的所有示例都没有将数据保存回数据库/网络服务,这正是我想要完成的。

我应该在哪里使用 MVVM 中的 HttpClient 调用我的 Web API?当用户更改 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));
        }
    }
}

【问题讨论】:

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


    【解决方案1】:

    这不是试图回答这个问题,而是试图向问题作者解释他们的问题与本网站无关。

    您将 WPF 与数据持久性混淆了……两者完全不相关。

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

    另一方面:

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

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

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


    更新>>>

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

    话虽如此,从更标准的开发角度来看,习惯上将数据访问层与 UI 层(MVVM 中的 V)、业务数据模型层(MVVM 中的 M)和业务逻辑分开(您在 MVVM 中的虚拟机)。这种分离可以在小型应用程序中使用文件夹,也可以在大型应用程序中使用项目。这称为separation of concerns


    最终更新>>>

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

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

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

    但是,由于这只是我的意见,其他人会有不同的意见,因此您的问题不可能有一个正确的答案。这就是为什么这些类型的主观问题在 Stack Overflow 上被认为是题外话。

    【讨论】:

    • 这不是关于保存数据的问题。我的 Web API 正在工作,我可以使用来自 Fiddler 的数据来保存数据。我想知道我应该在 MVVM 架构中的哪里调用我的 Web API。我试图重新表述这个问题以强调这一点。
    • 评论更新:我已经把我的担忧分开了,觉得问题已经说得很清楚了。在问题中,我提到了我的表示层(使用 MVVM 的 WPF 应用程序)和我的应用程序层(Web API)。在应用层之下还有其他层,比如数据访问层。基本上我只想知道你在 MVVM 中的哪个位置调用/使用 Web 服务。
    【解决方案2】:

    我想你现在已经解决了你的问题,但为了帮助以后可能出现的其他人,我会试一试。有很多方法可以解决这个问题(当然)。

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

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

    简单问题的简单解决方案。 基本问题是您的“详细视图”过于直接绑定到主控。对于这个简单的示例,您所说的“感觉不对”的解决方案可能是最好的,因为任何其他解决方案都会增加可能无用的复杂性。在一个非常简单的应用程序中,我认为可以忍受一些代码异味。如果我只是在树林里徒步一个小时,没有人会关心我是否穿了我肮脏、发臭的靴子袜。我不想在去这次短途徒步旅行之前把它们洗干净。

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

    现在。在某些时候,您需要代码来更改显示的详细数据(同样,而不是直接绑定)。我使用在 itemVM 上的 IsSelected 属性更改时触发的事件处理程序。然后,我只是异步保存数据。 Here 是一篇解释如何做到这一点的文章。

    另一种选择是等到应用程序关闭或其他一些有用的事件来保存您的数据。这在很多情况下可能并不实用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-31
      • 1970-01-01
      • 1970-01-01
      • 2019-05-22
      相关资源
      最近更新 更多