【问题标题】:Data from ViewModel is not binding to XAML from PageLoad EventViewModel 中的数据未绑定到 PageLoad 事件中的 XAML
【发布时间】:2020-12-24 01:31:10
【问题描述】:

我是 MVVM 架构的新手。我正在构建一个 UWP 应用程序。我基本上有一个 View(XAML)、代码背后 (Xaml.cs)、ViewModel 和数据服务。

我的视图/XAML 如下所示:

<Page
    x:Class="SnapBilling.SyncModule.SyncView"
    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:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" 
    mc:Ignorable="d" Loaded="Page_Loaded"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    
    
    <Grid>
        <Grid.Resources>
            <!--DataTemplate for Published Date column defined in Grid.Resources.  PublishDate is a property on the ItemsSource of type DateTime -->
            <DataTemplate x:Key="ProgressTemplate" >
                <ProgressBar x:Name="progressBar1" Value="{Binding Value.ProgressPercentage}" Maximum="100" Margin="20"/>
            </DataTemplate>
            
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*" />
            <RowDefinition Height="2*" />
        </Grid.RowDefinitions>
        <controls:DataGrid x:Name="BackupSummaryDataGrid" 
                            Grid.Row="0"
                            Margin="40"
                            ItemsSource="{x:Bind DataContext.UploadProgressInfoDict}"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            AlternatingRowBackground="Transparent"
                            AreRowDetailsFrozen="False"
                            AreRowGroupHeadersFrozen="True"
                            AutoGenerateColumns="False"
                            CanUserReorderColumns="True"
                            CanUserResizeColumns="True"
                            ColumnHeaderHeight="32"
                            FrozenColumnCount="0"
                            GridLinesVisibility="None"
                            HeadersVisibility="Column"
                            HorizontalScrollBarVisibility="Visible"
                            IsReadOnly="False"
                            MaxColumnWidth="400"
                            RowDetailsVisibilityMode="Collapsed"
                            RowGroupHeaderPropertyNameAlternative="Range"
                            SelectionMode="Extended"
                            VerticalScrollBarVisibility="Visible"
                            >

            <controls:DataGrid.Columns>
                <controls:DataGridTextColumn Tag="SyncType" Header="Sync Type" Binding="{Binding Key}" IsReadOnly="True"  />
                <controls:DataGridTextColumn Tag="remaining" Header="Pending Items" Binding="{Binding Value.remainingNow}" IsReadOnly="True"  />
                <controls:DataGridTemplateColumn Header="% remaining" CellTemplate="{StaticResource ProgressTemplate}" />
                <controls:DataGridTextColumn Header="Status" Binding="{Binding Value.ProgressMessage}" IsReadOnly="True"/>

            </controls:DataGrid.Columns>
            
        </controls:DataGrid>
    </Grid>
</Page>

现在,当页面/视图 xaml 加载时,它调用 xaml 类的构造函数,我们在其中初始化组件并使用视图模型对象设置数据上下文。这是类后面的代码,

public sealed partial class SyncView : Page, IView
{
    public SyncView()
    {
        this.InitializeComponent();
        DataContext = new SyncViewModel(ServiceLocator.Current.GetService<ICommonServices>());
    }
    
    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
    
    }
}

现在DataContext = new SyncViewModel(ServiceLocator.Current.GetService&lt;ICommonServices&gt;()); 获取一个已创建的 ViewModel 对象并正确绑定到数据上下文。

问题

当我从Page_Loaded 事件而不是下面的构造函数设置数据上下文时,viewmodel 对象没有绑定到页面的数据上下文。

private void Page_Loaded(object sender, RoutedEventArgs e)
        {
        DataContext = new SyncViewModel(ServiceLocator.Current.GetService<ICommonServices>());

        }

如何解决?

【问题讨论】:

    标签: c# mvvm data-binding uwp uwp-xaml


    【解决方案1】:

    所以代码执行的顺序是

    1. 构造函数调用
    2. 查看元素创建
    3. 绑定
    4. 页面加载事件(仅在添加所有子项时发生)

    发生的情况是,当您在构造函数中设置DataContext 时,DataContext 不为空,但是当您在Page_Loaded 中设置DataContext 时,绑定将与@987654325 一起发生@ 为 null,因此您在视图中看不到任何数据。

    现在,如果可以的话,我会建议您在绑定之前在构造函数中初始化视图模型。但是,如果由于某种原因您需要将其绑定到 Page_Loaded 事件中,您需要一种方法来告诉您视图在其更改时更新值。

    幸运的是,框架已经为此提供了解决方案,您可以在 ViewModel 上使用INotifyPropertyChanged 接口,以便它可以通知视图有关属性值的更改,在您的情况下,我猜是Value.ProgressPercentage

    但是您必须编写一个事件处理程序来相应地更新您的视图
    像这样的

     private void OnViewModelPropertyChange(object sender, PropertyChangedEventArgs e)
            {
                switch (e.PropertyName)
                {
                    case nameof(ViewModel.prop1):
                        // do something
                        break;
                    case nameof(ViewModel.prop2):
                        // do something else
                        break;
                }
            }
    

    这就是为什么我建议您改用数据绑定,这不是超级复杂,但它会为您节省几行额外的编码。

    【讨论】:

    • 我已经使用了 INotifyPropertyChanged。但是我猜你的解决方案的前两段对我有用。显然 datacontext 之前没有正确设置。
    【解决方案2】:

    现在在后面的代码中:

    public SyncView()
    {
     this.Loaded += SyncView_Loaded;  
    }
    private void SyncView_Loaded(object sender, RoutedEventArgs e)
    {
     this.InitializeComponent();
     DataContext = new SyncViewModel(ServiceLocator.Current.GetService<ICommonServices>());
    }
    

    在 XAML 中:

    ItemsSource="{Binding UploadProgressInfoDict}"
    

    原因:之前我创建了一个视图模型对象(例如 VM)并将其保存在代码隐藏类的属性中,然后我使用该属性设置数据上下文。后来我将 itemssource 与该对象的 UploadProgressInfoDict 绑定,例如

    ItemsSource="{Binding VM.UploadProgressInfoDict}"

    删除了这块,它工作正常!

    【讨论】:

      猜你喜欢
      • 2013-02-11
      • 2017-12-14
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      • 2013-08-07
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      相关资源
      最近更新 更多