【问题标题】:ListView not updating after ObservableCollection is changed on Button Click在按钮单击上更改 ObservableCollection 后 ListView 未更新
【发布时间】:2015-02-02 00:56:17
【问题描述】:

我有一个ListView,我正在使用RelayCommand 更新按钮点击。如果我在ViewModel 的构造函数中将项目添加到observableCollectionListView 将得到更新,但如果我在单击按钮后在方法中执行此操作则不会。

我花了很多时间研究 StackOverflow,虽然有很多相关问题我找不到答案。困扰我并且我无法理解的是,当我在构造函数中添加值时它会起作用。

我正在使用ObservableCollection

DataContext 设置为在页面级别查看模型 在 XAML 中将 ObservableCollection 绑定到 ListView

XAML 代码

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyFare"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModel="using:MyFare.ViewModel"
x:Class="MyFare.MainPage"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding Main, Mode=OneWay, Source={StaticResource Locator}}">

<Grid Height="640" Margin="0,0.333,0,-0.333" VerticalAlignment="Top">
    <TextBlock x:Name="title" Text="View My Fare"  Margin="0,10,0,603"/>
    <TextBox x:Name="txtCurrentValue" InputScope="Number" PlaceholderText="Enter your Current Balance" Margin="0,53,0,0" Text="{Binding CurrentBalance, Mode=TwoWay}"/>
    <Button Content="Show Fares" HorizontalAlignment="Left" Margin="96,113,0,0" VerticalAlignment="Top" Command="{Binding ShowFaresCommand, Mode=OneWay}" CommandParameter="{Binding CurrentBalance}" />
    <ListView x:Name="nbc" SelectionMode="Single" Margin="10,182,10,150" ItemsSource="{Binding Charges}">
        <ListView.Resources>
            <DataTemplate x:Key="FareTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding AmountToRecharge}" TextAlignment="Right" Grid.ColumnSpan="4" Margin="0,0,-28,0" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource TextStyleLargeFontSize}"></TextBlock>
                    <TextBlock Text="{Binding BonusAmount}" TextAlignment="Right" Margin="118.333,0,-128.333,0" Grid.Column="3" FontSize="{StaticResource TextStyleLargeFontSize}"/>
                    <TextBlock Text="{Binding NewBalance}" TextAlignment="Right" Margin="118,0,-229.333,0" Grid.Column="3" FontSize="{StaticResource TextStyleLargeFontSize}"/>
                    <TextBlock Text="{Binding NumberofRides}" TextAlignment="Right" Margin="298,0,-308.333,0" Grid.Column="3" FontSize="{StaticResource TextStyleLargeFontSize}"/>
                </Grid>
            </DataTemplate>
            <ItemsPanelTemplate x:Key="FaresPanelTemplate">
                <VirtualizingStackPanel Orientation="Vertical"></VirtualizingStackPanel>
            </ItemsPanelTemplate>
            <DataTemplate x:Key="headerTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="90" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Amount to Recharge" Grid.Column="0" TextWrapping="WrapWholeWords" FontFamily="{StaticResource PivotHeaderItemFontFamily}" FontSize="{StaticResource ContentControlFontSize}"/>
                    <TextBlock Text="Bonus Amount" Grid.Column="1" TextWrapping="WrapWholeWords" FontFamily="{StaticResource PivotHeaderItemFontFamily}" FontSize="{StaticResource ContentControlFontSize}"/>
                    <TextBlock Text="New Balance" Grid.Column="2" TextWrapping="WrapWholeWords" FontFamily="{StaticResource PivotHeaderItemFontFamily}" FontSize="{StaticResource ContentControlFontSize}"/>
                    <TextBlock Text="Number of Rides" Grid.Column="3" TextWrapping="WrapWholeWords" FontFamily="{StaticResource PivotHeaderItemFontFamily}" FontSize="{StaticResource ContentControlFontSize}"/>
                </Grid>
            </DataTemplate>
        </ListView.Resources>
        <ListView.HeaderTemplate>
            <StaticResource ResourceKey="headerTemplate"/>
        </ListView.HeaderTemplate>
        <ListView.ItemsPanel>
            <StaticResource ResourceKey="FaresPanelTemplate"/>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <StaticResource ResourceKey="FareTemplate"/>
        </ListView.ItemTemplate>

        <ListView.DataContext>
            <ViewModel:MainViewModel/>
        </ListView.DataContext>
    </ListView>
</Grid>

查看模型

 using MyFareFare.Library;
 using GalaSoft.MvvmLight;
 using GalaSoft.MvvmLight.Command;
 using System;
 using System.Collections.ObjectModel;
 using System.Windows.Input;

 namespace MyFareFare.ViewModel {
 /// <summary>
 /// This class contains properties that the main View can data bind to.
 /// <para>
 /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
 /// </para>
 /// <para>
 /// You can also use Blend to data bind with the tool's support.
 /// </para>
 /// <para>
 /// See http://www.galasoft.ch/mvvm
 /// </para>
 /// </summary>
 public class MainViewModel : ViewModelBase
 {
     /// <summary>
     /// The <see cref="BonusChargesValue" /> property's name.
     /// </summary>
     public const string ChargesListPropertyName = "ChargeList";

     public const string PageNamePropertyName = "PageName";

     public const string CurrentBalancePropertyName = "CurrentBalance";

     public const string ButtonTextPropertyName = "ButtonText";

     private string _pageName = "My Fare";

     private string _currentBalance = "";

     private string _buttonText = "Show Fares";

     private RelayCommand _showFaresCommand; 

     public ObservableCollection<BonusChargesValue> _charges = null;

     public string PageName
     {
         get
         {
             return _pageName;
         }

         set
         {
             if (_pageName == value)
             {
                 return;
             }

             //  RaisePropertyChanging(ChargesListPropertyName);
             _pageName = value;
             RaisePropertyChanged(PageNamePropertyName);
         }
     }

     public string ButtonText
     {
         get
         {
             return _buttonText;
         }
         set
         {
             if (_buttonText == value)
             {
                 return;
             }

             //  RaisePropertyChanging(ChargesListPropertyName);
             _buttonText = value;
             RaisePropertyChanged(ButtonTextPropertyName);
         }
     }

     public string CurrentBalance
     {
         get
         {
             return _currentBalance;
         }

         set
         {
             if (_currentBalance == value)
             {
                 return;
             }

             //  RaisePropertyChanging(ChargesListPropertyName);
             _currentBalance = value;
             RaisePropertyChanged(CurrentBalancePropertyName);
         }
     }

     /// <summary>
     /// Sets and gets the Charges property.
     /// Changes to that property's value raise the PropertyChanged event. 
     /// </summary>
     public ObservableCollection<BonusChargesValue> Charges
     {
         get
         {
             return _charges;
         }

         set
         {
             if (_charges == value)
             {
                 return;
             }

            // RaisePropertyChanging(ChargesListPropertyName);
             _charges = value;
             RaisePropertyChanged(ChargesListPropertyName);
         }
     }

     public RelayCommand ShowFaresCommand
     {
         get;
         set;
     } 

     //public RelayCommand ShowFaresCommand 
     //{
     //    get
     //    {
     //        return _showFaresCommand
     //          ?? (_showFaresCommand = new RelayCommand(
     //              ()=> 
     //              {
     //                  _charges = new ObservableCollection<BonusChargesValue>();
     //                  CalculateMetroFare cmcf = new CalculateMetroFare();
     //                  if (!string.IsNullOrWhiteSpace(CurrentBalance))
     //                  {
     //                      _charges = cmcf.Add2ExistingCard(Convert.ToInt32(CurrentBalance));
     //                  }

     //              }));

     //    }  
     //}

    // public RelayCommand ShowFares { get; set; }

     /// <summary>
     /// Initializes a new instance of the MainViewModel class.
     /// </summary>
     public MainViewModel()
     {

         _charges = new ObservableCollection<BonusChargesValue>();
         ShowFaresCommand = new RelayCommand(GetValues, () => { return true; });

           // if I un-comment the below section the observable is working fine.
       //Using lambda is not helping either 

        /* if (IsInDesignMode)
         {
             // Code runs in Blend --> create design time data.
            // BonusChargesValue bnc = new BonusChargesValue();
             _charges = new ObservableCollection<BonusChargesValue>();
             _charges.Add(new BonusChargesValue { AmountToRecharge = 10.0, BonusAmount = 5, NewBalance = 15, NumberofRides = 5 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 12.0, BonusAmount = 6, NewBalance = 17, NumberofRides = 6 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 14.0, BonusAmount = 7, NewBalance = 19, NumberofRides = 7 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 16.0, BonusAmount = 8, NewBalance = 21, NumberofRides = 8 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 18.0, BonusAmount = 9, NewBalance = 23, NumberofRides = 9 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 10.0, BonusAmount = 5, NewBalance = 15, NumberofRides = 5 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 12.0, BonusAmount = 6, NewBalance = 17, NumberofRides = 6 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 14.0, BonusAmount = 7, NewBalance = 19, NumberofRides = 7 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 16.0, BonusAmount = 8, NewBalance = 21, NumberofRides = 8 });
             _charges.Add(new BonusChargesValue { AmountToRecharge = 18.0, BonusAmount = 9, NewBalance = 23, NumberofRides = 9 });
         }
         else
         {
             // Code runs "for real"
             _charges = new ObservableCollection<BonusChargesValue>();
           //  ShowFaresCommand = new RelayCommand(GetValues, () => { return true; });

             ShowFaresCommand = new RelayCommand(() =>
             {


                 CalculateMetroFare cmcf = new CalculateMetroFare();
                 if (!string.IsNullOrWhiteSpace(CurrentBalance))
                 {
                     var chr = cmcf.Add2ExistingCard(Convert.ToInt32(CurrentBalance));

                     foreach (BonusChargesValue bncv in chr)
                     {
                         Charges.Add(bncv);
                     }

                 }
             });

             //_charges = new ObservableCollection<BonusChargesValue>();
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 10.0, BonusAmount = 5, NewBalance = 15, NumberofRides = 5 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 12.0, BonusAmount = 6, NewBalance = 17, NumberofRides = 6 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 14.0, BonusAmount = 7, NewBalance = 19, NumberofRides = 7 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 16.0, BonusAmount = 8, NewBalance = 21, NumberofRides = 8 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 18.0, BonusAmount = 9, NewBalance = 23, NumberofRides = 9 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 10.0, BonusAmount = 5, NewBalance = 15, NumberofRides = 5 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 12.0, BonusAmount = 6, NewBalance = 17, NumberofRides = 6 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 14.0, BonusAmount = 7, NewBalance = 19, NumberofRides = 7 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 16.0, BonusAmount = 8, NewBalance = 21, NumberofRides = 8 });
             //_charges.Add(new BonusChargesValue { AmountToRecharge = 18.0, BonusAmount = 9, NewBalance = 23, NumberofRides = 9 });
         } */


     }
     private void GetValues()
     {

         CalculateMetroFare cmcf = new CalculateMetroFare();
         if (!string.IsNullOrWhiteSpace(CurrentBalance))
         {
             var chr = cmcf.Add2ExistingCard(Convert.ToInt32(CurrentBalance));

             foreach (BonusChargesValue bncv in chr)
             {
                 Charges.Add(bncv);
             }

         }

     }
 }

我不确定我做错了什么。任何帮助或指针表示赞赏。

【问题讨论】:

    标签: xaml listview windows-phone-8 mvvm-light win-universal-app


    【解决方案1】:

    我可以在这里看到几件事:

    首先你的ChargesListPropertyName 是错误的,它应该是“Charges”而不是“ChargeList”。 如果您使用的是 MVVM Light,有更好的方法来调用 PropertyChanged 可以防止您再次犯这种错误(稍后我会让您检查)。

    然后你有你的公共ObservableCollection Charges,它是 _charges 的访问者,也是公共的。您应该将 _charges 设置为私有(并将其设置为 null 是没有用的)。

    最后,您的 ItemsSource 设置为观看 Charges。因此,无论您在视图模型的构造函数之外如何更新 _charges,列表都永远不会知道发生了什么。我的意思是您应该始终更新 Charges 而不是 _charges。

    进行这些修改并告诉我们是否有帮助。如果没有,请更新您的代码以向我们展示您所做的修改。

    【讨论】:

    • 感谢您的意见。该建议没有奏效。如您所见,我已经在 GetValue 方法中更新“Charges”,而不是 _charges。我也将“ChargesListPropertyName”更改为“Charges”。我看到值被添加到 Charges observable 中,但只有视图没有更新。
    • 请相应地更新您在此页面上的代码,以便其他人可以更好地看到需要更改的内容。
    猜你喜欢
    • 2019-10-25
    • 2018-06-09
    • 2021-03-18
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多