在更新可观察集合中的对象时,Xaml视图不会更新

Ric*_*oth 1 xaml uwp uwp-xaml

我正在尝试开始使用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>
Run Code Online (Sandbox Code Playgroud)

代码背后

    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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对象类

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));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Kai*_*und 8

编译绑定默认为OneTime,因此它们仅在最初设置且不监听更改.

将其更改为:

<ListView ItemsSource="{x:Bind ViewModel.Collection, Mode=OneWay}">...
Run Code Online (Sandbox Code Playgroud)

此Build会话中查找有关Compiled Bindings的完整概述.

  • 谢谢你。我必须在每个绑定中添加“Mode=OneWay”。现在它起作用了。从来没见有人提过这个。我想这是因为编译绑定是相当新的。 (2认同)
  • 实际上,如果你观看有关它的构建视频,他们会花很多时间在这个特定的变化上.接下来可能让你想知道的是,编译的绑定不会检测继承的接口.就像你有一个实现了更改INotifyProperty的基本ViewModel一样,你必须显式地将接口添加到每个派生类型,以便编译绑定工作. (2认同)