【问题标题】:Xaml view not updating while updating objects in observable collection更新可观察集合中的对象时,Xaml 视图未更新
【发布时间】:2016-06-03 04:57:45
【问题描述】:

我正在尝试开始使用 UWP 应用程序,尽管我对 xaml 和 C# 完全陌生。这个问题现在花了我几个小时。我已经看过很多教程,并在 stackoverflow 上阅读了类似问题的答案,但到目前为止对我没有任何帮助。

我有一个 ListView,它具有与 ObservableCollection 的数据绑定。当我启动应用程序时,它会正确显示此集合中的对象。当我向集合中添加新对象或删除现有对象时,ListView 会正确更新。但是当我修改对象时,虽然我实现了 INotifyPropertyChanged 并在属性更改时触发事件,但它并没有更新。

代码如下:

查看 Xaml

<Page
x:Class="Prophecy_Challenge_Tracker.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Prophecy_Challenge_Tracker"
xmlns:data="using:Prophecy_Challenge_Tracker.persistence"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel x:Name="firstStack" Margin="8 ,32 ,0, 0 " Width="350" >
        <ListView ItemsSource="{x:Bind ViewModel.Collection}"   VerticalAlignment="Center" Background="Yellow" CanReorderItems="True">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="data:Challenge" >
                    <Grid  Background="Green" >
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Button  Content="+" Grid.Column="0"/>
                        <TextBlock  Grid.Column="1" Text="{x:Bind ChallengeName}" VerticalAlignment="Center"/>
                        <TextBlock Grid.Column="2"  Text="{x:Bind Progress}" VerticalAlignment="Center" HorizontalAlignment="Center" />
                        <Button Grid.Column="3" Content="X"  />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Content="Add" Click="add"/>
        <Button Content="Delete" Click="delete"/>
        <Button Content="Update Progress" Click="updateProgress"/>
    </StackPanel>
</Grid>

代码隐藏

    using Prophecy_Challenge_Tracker.persistence;
using Prophecy_Challenge_Tracker.viewmodel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace Prophecy_Challenge_Tracker
{
    /// <summary>
    /// Eine leere Seite, die eigenständig verwendet oder zu der innerhalb eines Rahmens navigiert werden kann.
    /// </summary>
    public sealed partial class MainPage : Page
    {

        public MainPage()
        {
            this.ViewModel = new Viewmodel();
            this.InitializeComponent();
            this.DataContext = ViewModel;
        }

        public Viewmodel ViewModel { get; set; }

        int counter = 2;
        private void add(object sender, RoutedEventArgs e)
        {
            counter++;
            var c = new Challenge();
            c.ChallengeName = "Additional Line";
            c.Progress = counter + "/7";
            ViewModel.Collection.Add(c);
        }

        private void delete(object sender, RoutedEventArgs e)
        {
         var c =   ViewModel.Collection.ElementAt(ViewModel.Collection.Count - 1);
            ViewModel.Collection.Remove(c);
            counter--;
        }

        private void updateProgress(object sender, RoutedEventArgs e)
        {
            var c = ViewModel.Collection.ElementAt(ViewModel.Collection.Count - 1);
            int index = ViewModel.Collection.IndexOf(c);
            counter++;
            Debug.WriteLine("CurrentName: " + c.Progress);
            c.Progress = counter + "/7";
            Debug.WriteLine("New Name: " + c.Progress);
        }
    }
}

对象类

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Prophecy_Challenge_Tracker.persistence
{
    public class Challenge : INotifyPropertyChanged
    {
        private string challengeName;
        public string ChallengeName
        {
            get { return challengeName; }
            set
            {
                if (value != challengeName)
                {
                    challengeName = value;
                    NotifyPropertyChanged("ChallengeName");
                }
            }
        }

        private string progress = "";
        public string Progress
        {
            get { return progress; }
            set
            {
                if (value != progress)
                {
                    progress = value;
                    NotifyPropertyChanged("Progress");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
        {
            System.Diagnostics.Debug.WriteLine("Shortly before update. PropertyName = " + propertyName);
            if (PropertyChanged != null)
            {
                System.Diagnostics.Debug.WriteLine("Update now");
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

视图模型

using Prophecy_Challenge_Tracker.persistence;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Prophecy_Challenge_Tracker.viewmodel
{
    public class Viewmodel
    {

        public ObservableCollection<Challenge> Collection { get; set; }

        public Viewmodel()
        {
            System.Diagnostics.Debug.WriteLine("New Viewmodel is being created");
            Collection = new ObservableCollection<Challenge>();
            Challenge c = new Challenge();
            c.ChallengeName = "First Line";
            c.Progress = "1/5";
            Collection.Add(c);
            c = new Challenge();
            c.ChallengeName = "Second Line";
            c.Progress = "2/5";
            Collection.Add(c);
        }
    }
}

【问题讨论】:

    标签: xaml uwp uwp-xaml


    【解决方案1】:

    Compiled Bindings 默认为OneTime,因此它们仅在初始设置,不监听更改。

    改成:

    <ListView ItemsSource="{x:Bind ViewModel.Collection, Mode=OneWay}">...
    

    this Build session 中找到有关已编译绑定的良好概述。

    【讨论】:

    • 谢谢。我必须在每个绑定中添加“Mode=OneWay”。现在它起作用了。从来没见过有人提过这个。我猜这是因为编译的绑定相当新。
    • 实际上,如果您观看有关它的构建视频,他们会在此特定更改上花费大量时间。 ? 接下来可能会让你想知道的是,编译的绑定不检测继承的接口。就像如果你有一个实现 INotifyProperty 的基本 ViewModel 发生了变化,你必须显式地将接口添加到每个派生类型才能使编译的绑定工作。
    • @Kai,能否请您发布讨论此绑定更改的视频的 URI。从 WPF 过渡到 UWP 时,听起来有很多问题。
    • 当然。我将其添加到答案中。
    猜你喜欢
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多