【问题标题】:How do I persist the value of the Textbox Text property of a user control when switching from one view to another?从一个视图切换到另一个视图时,如何保持用户控件的 Textbox Text 属性的值?
【发布时间】:2020-07-01 10:54:53
【问题描述】:

学习 C#,特别是 WPF 和 MVVM 框架。我正在创建一个基本项目,它提供一个带有 contentcontrol 绑定的 MainWindow。直截了当。

我有 2 个视图,每个视图都有一个文本框。我在 MainWindow 上有 2 个按钮,每个按钮都允许我在视图之间切换。但是,当我在文本框中输入数据、切换视图并返回时,数据就消失了。如何持久保存这些数据以供以后使用?

相关代码:

MainWindow.xaml

<Window x:Class="TestDataRetention.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestDataRetention"
        xmlns:views="clr-namespace:TestDataRetention.Views"
        xmlns:viewmodels="clr-namespace:TestDataRetention.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate DataType="{x:Type viewmodels:View1ViewModel}">
            <views:View1View DataContext="{Binding}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewmodels:View2ViewModel}">
            <views:View2View DataContext="{Binding}"/>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="60"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Right">
            <Button x:Name="View1Button" Margin="10" Width="80" Content="View1" Click="View1Button_Click"/>
            <Button x:Name="View2Button" Margin="10" Width="80" Content="View2" Click="View2Button_Click"/>
        </StackPanel>
        <ContentControl x:Name="Content" Grid.Row="0" Content="{Binding}"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using TestDataRetention.ViewModels;

namespace TestDataRetention
{
    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void View1Button_Click(object sender, RoutedEventArgs e)
        {
            DataContext = new View1ViewModel();
        }

        private void View2Button_Click(object sender, RoutedEventArgs e)
        {
            DataContext = new View2ViewModel();
        }
    }
}

View1View.xaml

<UserControl x:Class="TestDataRetention.Views.View1View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TestDataRetention.Views"
             xmlns:vm="clr-namespace:TestDataRetention.ViewModels"
             mc:Ignorable="d" 
             FontSize="24"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.DataContext>
        <vm:View1ViewModel/>
    </UserControl.DataContext>
    <Grid Background="AliceBlue">
        <StackPanel>
            <Label HorizontalAlignment="Center" Content="Enter View1 Stuff"/>
            <TextBox x:Name="View1TextBox" Width="400" Height="50" Text="{Binding View1Words}" />
        </StackPanel>
    </Grid>
</UserControl>

View1View.xaml.cs

using System.Windows.Controls;
using TestDataRetention.ViewModels;

namespace TestDataRetention.Views
{
    public partial class View1View : UserControl
    {
        public View1View()
        {
            InitializeComponent();

            this.DataContext = new View1ViewModel();
        }
    }
}

View2 显然与 View1 相同,但具有相应的变量。

【问题讨论】:

    标签: c# wpf mvvm data-binding


    【解决方案1】:

    虽然也可能有一种方法让 wpf 为您缓存它,但您也可以轻松地正确保存它,然后随意使用输入。

    在这里查看两种方法:

    How to save user inputed value in TextBox? (WPF, XAML)

    【讨论】:

    • 你好!谢谢(你的)信息。我操作设置文件就好了。现在我遇到的问题是按钮驻留在 MainWindow.cs 中,那么如何在单击按钮时将用户控件中的属性写入设置文件,该属性在 MainWindow.cs 中不直接可用?
    • 就像 M. Elghamry 所说,每次单击按钮时都会创建一个新对象,这使得这一切变得相当乏味。您需要在旧对象被销毁之前调用 Settings.Default.Save() 以保存信息,即使使用双向绑定也是如此。
    • 谢谢。我在 settings.settings 文件中添加了所有需要的变量,并确保调用了 save 方法。这让我克服了困难!感谢您的帮助。
    【解决方案2】:

    快速浏览一下,您每次单击按钮时都会创建 new ViewModel,这将始终为您的 DataContext 创建新的 ViewModel,而不是使用原来的。

    此外,您的代码中的这个 sn-p 将为您的控件的 DataContext 创建 new ViewModel,而不管父控件具有哪个:

    <UserControl.DataContext>
        <vm:View1ViewModel/>
    </UserControl.DataContext>
    

    我不确定你如何在这里使用你的DataTemplate:

    <DataTemplate DataType="{x:Type viewmodels:View1ViewModel}">
        <views:View1View DataContext="{Binding}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewmodels:View2ViewModel}">
        <views:View2View DataContext="{Binding}"/>
    </DataTemplate>
    

    但通常,作为对 MVVM 项目建模的指导,请始终牢记 XAML 代码在编译时会转换为 C#。所以当你写像&lt;vm:View1ViewModel/&gt;这样的东西时,你实际上是在写new View1ViewModel()。

    因此,要使用从其父控件继承的 DataContext,您只需将 &lt;UserControl DataContext="{binding}" 用于您的 UserControl。

    对于您的按钮单击,您必须为之前创建的 ViewModel 保留一个指针,并在需要时将其分配给 DataContext,我建议您仅在需要时创建这些 ViewModel,以最大限度地减少大型应用程序中的内存消耗,例如:

    private View1ViewModel m_View1VM = null;
    private void View1Button_Click(object sender, RoutedEventArgs e)
    {
        if (m_View1VM is null)
            m_View1VM = new View1ViewModel();
        this.DataContext = m_View1VM;
    }
    

    【讨论】:

    • 感谢您的回复。我如何绕过每次调用一个新的 ViewModel?或者,我可以将属性保存到内存并让它们重建视图吗?此外,为了回答有关我如何使用 DataTemplates 的评论,如果我将该部分注释掉并运行程序,当我单击按钮时,它只会在 ViewModel 路径的内容控件中显示一个字符串。我被教导那里需要。另外,关于 this.DataContext 与 ,这不只是一个偏好问题吗?
    • 不客气!请注意我更正了最后的代码 sn-p。我现在明白你使用 DataTemplate 的观点了。祝你好运!
    • 关于&lt;vm:View1ViewModel/&gt;和this.DataContext之间的区别,这里的重点是您需要访问您的控件从其父控件获得的DataContext,&lt;vm:View1ViewModel/&gt;将创建新的ViewModel,因此您赢了'无法访问保存到 Button Click 中提供的原始创建的 ViewModel 的数据。在修改了DataTemplate 的代码和用法之后,您不需要&lt;UserControl DataContext="{binding}",因为您的DataTemplate 已经分配了它。
    • 为了绕过每次创建新的 ViewModel,你会注意到在最后的代码 sn-p 中,m_View1VM 是在你的类的全局空间中而不是在方法内,所以,当你调用 Button点击,该方法会检查该ViewModel之前是否创建过,如果没有创建新的,如果创建了,则使用它。
    猜你喜欢
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 2015-03-23
    • 2011-04-13
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2015-05-09
    相关资源
    最近更新 更多