C# 在Win Phone 8应用程序中,PropertyChanged事件处理程序始终为空

C# 在Win Phone 8应用程序中,PropertyChanged事件处理程序始终为空,c#,.net,wpf,xaml,windows-phone-8,C#,.net,Wpf,Xaml,Windows Phone 8,当我点击这个简单的Win Phone 8应用程序上的“添加一些东西”按钮时(使用VS 2012 Pro构建-这就是我所拥有的),什么都没有发生。为什么? 此示例代码的回购在bitbucket.org上,网址为: MainPage.xaml包含: <phone:PhoneApplicationPage x:Class="TestItemsControlInWinPhone8App.MainPage" xmlns="http://schemas.microsoft.com/winfx/200

当我点击这个简单的Win Phone 8应用程序上的“添加一些东西”按钮时(使用VS 2012 Pro构建-这就是我所拥有的),什么都没有发生。为什么?

此示例代码的回购在bitbucket.org上,网址为:

MainPage.xaml
包含:

<phone:PhoneApplicationPage
x:Class="TestItemsControlInWinPhone8App.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">

<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
        <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Button x:Name="AddSomeThing"
                    Content="Add Some Thing"
                    Grid.Row="0"
                    Click="AddSomeThing_Click"/>
            <ItemsControl x:Name="LotsOfThingsItemsControl"
                          Grid.Row="1"
                          ItemsSource="{Binding Mode=OneWay}"
                          FontSize="{StaticResource PhoneFontSizeSmall}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Height="Auto" Width="Auto"
                          VerticalAlignment="Center"
                          HorizontalAlignment="Center"
                          Background="Orange">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Row="0" Text="{Binding Path=Id, Mode=OneWay}"/>
                            <TextBlock Grid.Row="1"
                                       Text="------------------------"/>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Grid>
    </StackPanel>

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

    </Grid>
</Grid>

</phone:PhoneApplicationPage>
请注意,在
页面中
构造函数
this.DataContext=new LotsOfThings(5)工作,当第一次显示
页面时,将显示5个
对象

需要明确的是,不起作用的是后一次调用
AddSomeThing\u click()
按钮处理程序将向
LotsOfThings
添加另一个
对象,但只显示原来的5个
对象;仅此而已,即使根据调试器,
LotsOfThings
上存在更多的
Thing
对象

使用调试器时,我注意到每当调用
OnPropertyChanged(…)
时,处理程序
都是
null
。这显然很重要,但我不知道为什么会发生这种情况,因为此时我已经遵循了搜索web时所能找到的所有补救帮助

为什么?

Thing.cs的内容

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestItemsControlInWinPhone8App
{
public class Thing : INotifyPropertyChanged
{
    private string _Id = Guid.NewGuid().ToString();
    public string Id
    {
        get
        {
            return _Id;
        }
        set { }
    }

    #region Constructor
    public Thing()
    {
        this.OnPropertyChanged( "Id");
    }
    #endregion

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string pPropertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(pPropertyName));
        }
    }
    #endregion
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestItemsControlInWinPhone8App
{
class LotsOfThings : INotifyPropertyChanged, IList<Thing>
{
    private List<Thing> _things = new List<Thing>();
    public List<Thing> Things
    {
        get {
            return _things;
        }
        set { }
    }

    public LotsOfThings( int pNumberOfThings)
    {
        for( int x = 0; x < pNumberOfThings; x++){
            this.Add( new Thing());
        }
        OnPropertyChanged("Things");
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string pName)
    {
        System.ComponentModel.PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(pName));
        }
    }
    #endregion

    #region IList<T> methods
    public int IndexOf(Thing item)
    {
        return _things.IndexOf(item);
    }

    public void Insert(int index, Thing item)
    {
        _things.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _things.RemoveAt(index);
    }

    public Thing this[int index]
    {
        get
        {
            return _things[index];
        }
        set
        {
            _things[index] = value;
        }
    }

    public void Add(Thing item)
    {
        _things.Add(item);

        OnPropertyChanged("Things");
    }

    public void Clear()
    {
        _things.Clear();
    }

    public bool Contains(Thing item)
    {
        return _things.Contains(item);
    }

    public void CopyTo(Thing[] array, int arrayIndex)
    {
        _things.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _things.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(Thing item)
    {
        return _things.Remove(item);
    }

    public IEnumerator<Thing> GetEnumerator()
    {
        return _things.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _things.GetEnumerator();
    }
    #endregion
}
}
LotsOfThings.cs的内容

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestItemsControlInWinPhone8App
{
public class Thing : INotifyPropertyChanged
{
    private string _Id = Guid.NewGuid().ToString();
    public string Id
    {
        get
        {
            return _Id;
        }
        set { }
    }

    #region Constructor
    public Thing()
    {
        this.OnPropertyChanged( "Id");
    }
    #endregion

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string pPropertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(pPropertyName));
        }
    }
    #endregion
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestItemsControlInWinPhone8App
{
class LotsOfThings : INotifyPropertyChanged, IList<Thing>
{
    private List<Thing> _things = new List<Thing>();
    public List<Thing> Things
    {
        get {
            return _things;
        }
        set { }
    }

    public LotsOfThings( int pNumberOfThings)
    {
        for( int x = 0; x < pNumberOfThings; x++){
            this.Add( new Thing());
        }
        OnPropertyChanged("Things");
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string pName)
    {
        System.ComponentModel.PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(pName));
        }
    }
    #endregion

    #region IList<T> methods
    public int IndexOf(Thing item)
    {
        return _things.IndexOf(item);
    }

    public void Insert(int index, Thing item)
    {
        _things.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _things.RemoveAt(index);
    }

    public Thing this[int index]
    {
        get
        {
            return _things[index];
        }
        set
        {
            _things[index] = value;
        }
    }

    public void Add(Thing item)
    {
        _things.Add(item);

        OnPropertyChanged("Things");
    }

    public void Clear()
    {
        _things.Clear();
    }

    public bool Contains(Thing item)
    {
        return _things.Contains(item);
    }

    public void CopyTo(Thing[] array, int arrayIndex)
    {
        _things.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _things.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(Thing item)
    {
        return _things.Remove(item);
    }

    public IEnumerator<Thing> GetEnumerator()
    {
        return _things.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _things.GetEnumerator();
    }
    #endregion
}
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间TestItemsControlInWinPhone8App
{
类LotsOfThings:INotifyPropertyChanged,IList
{
私有列表_things=新列表();
公开物品清单
{
得到{
归还物品;
}
集合{}
}
公共LotsOfThings(整数)
{
对于(int x=0;x
如果您需要下载应用程序或使用更好的界面查看应用程序,您可以在此处找到:

多谢各位


另外,我已经阅读了Stackoverflow和网上其他地方关于传入
OnPropertyChanged()
方法的空处理程序以及我能找到的
ItemsControl
的用法的所有建议,并且我认为,我遵循了这些建议。

\u事情需要
可观察收集
<代码>列表
未实现
INotifyCollectionChanged
,因此在其内容更改时不会发出通知
ObservableCollection
Dos,这将使UI知道何时需要向列表中添加项目

做事情的简单、简单、标准的方法是将
可观测集合
作为属性公开。如果用新的集合替换整个集合,请升起
PropertyChanged(“Things”)
;添加/删除项目时,
ObservableCollection
将引发适当的事件,而无需您执行任何操作。有经验的WPF人员阅读您的代码时会知道他们在看什么

为了让它按照您的想法工作,您必须在改变
Things
集合的方法中调用
OnPropertyChanged(“Things”)
;我还没有测试过,但我认为它应该可以工作(原因可能是
Things
返回的实际集合对象没有更改;控件可能会看到这一点并选择不更新;但正如我所说,我还没有测试)。然后您可以将
东西
绑定到控件上的
项目资源
,也许它应该可以工作。但是,您可以让其他类更改
内容
,因为它是公共的。试图追查所有未解决的问题将是一场混乱。更易于使用
可观察采集


如果您想将
LotsOfThings
本身绑定到
ItemsSource
,您必须在
LotsOfThings
上实现
INotifyCollectionChanged
,手工重写这些内容会非常麻烦,我不确定它能给您带来什么好处。您只需将
LotsOfThings
作为
ObservableCollection
的子类,就可以免费使用一个完整的、防弹的
INotifyCollectionChanged
实现

\u事物
需要是
Obs