C# ItemsControl在数据更改为ObservableCollection后不更新<;T>;财产

C# ItemsControl在数据更改为ObservableCollection后不更新<;T>;财产,c#,xaml,uwp,C#,Xaml,Uwp,我有以下测试代码… XAML: 代码隐藏: namespace Test { public class MyData { public string FirstName { get; set; } public string Surname { get; set; } } public class LoadData { public static void Get_RowItems(Observable

我有以下测试代码… XAML:


代码隐藏:

namespace Test
{
    public class MyData
    {
        public string FirstName { get; set; }
        public string Surname { get; set; }
    }

    public class LoadData
    {
        public static void Get_RowItems(ObservableCollection<MyData> Items)
        {
            Items.Add(new MyData() { FirstName = "John", Surname = "Doe" });
        }
    }

    public sealed partial class MainPage : Page
    {
        private ObservableCollection<MyData> RowItems;

        public MainPage()
        {
            this.InitializeComponent();
            RowItems = new ObservableCollection<MyData>();
            LoadData.Get_RowItems(RowItems);
        }

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            RowItems[0].FirstName = "Bill";
        }
    }
}
名称空间测试
{
公共类MyData
{
公共字符串名{get;set;}
公共字符串姓氏{get;set;}
}
公共类装入数据
{
公共静态无效获取行项目(可观察集合项目)
{
添加(新的MyData(){FirstName=“John”,姓氏=“Doe”});
}
}
公共密封部分类主页面:第页
{
私人可观测收集项目;
公共主页()
{
this.InitializeComponent();
RowItems=新的ObservableCollection();
LoadData.Get_RowItems(RowItems);
}
私有无效开始按钮单击(对象发送者,路由目标)
{
行项目[0]。FirstName=“比尔”;
}
}
}
运行时,ItemsControl显示第一行数据(John Doe)

单击开始按钮时,基础数据将更改为Bill Doe(如预期的那样)

但是,ItemsControl顽固地继续显示:John Doe

我读过很多关于这类问题的文章,但是没有一个解决方案是有效的(如果我正确地实施了它们的话),所以现在我看不到实情


任何帮助都将不胜感激。

克莱门斯是正确的。此外,x:Bind的默认绑定是一次性绑定,因此它永远不会得到更新。相反,你需要的是:

<TextBlock Text="{x:Bind FirstName, Mode=OneWay}" Margin="10,0,5,0"/>


对于使用x:Bind的其他地方也是一样。

就像@Clemens所说的,您应该在
MyData
类中实现
INotifyPropertyChanged
事件,以便在类的属性发生更改时通知UI

public class MyData:INotifyPropertyChanged
{
    //public string FirstName { get; set; }
    private string firstName;

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value;
        OnPropertyChanged("FirstName");
        }
    }

    private string surName;

    public string Surname
    {
        get { return surName; }
        set { surName = value;
        OnPropertyChanged("Surname");

        }
    }

    //public string Surname { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
您不是在修改
可观测集合
本身(例如添加/删除项目),而是在该集合内的项目。
ObservableCollection
负责通知其自身的更改,而不是与其项目相关的更改。您应该在
MyData
类的
setter
中通知PropertyChange(“每个您的属性”),您的UI将被更新

并将
TextBlock
和“姓氏”属性的绑定更改为“单向”,因为默认情况下它设置为“一次性”:


根据提供的答案,您可以进一步为实体定义一个公共类,并以强类型方式通知视图属性值已更改:

public abstract class BaseEntity : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises the PropertyChanged event
    /// </summary>
    /// <param name="propertyName">Name of the property</param>
    public void OnPropertyChanged(string propertyName)
    {
        var ev = PropertyChanged;
        if (ev != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// Raises the PropertyChanged event
    /// </summary>
    /// <param name="expr">Lambda expression that identifies the updated property</param>
    public void OnPropertyChanged<TProp>(Expression<Func<BaseEntity, TProp>> expr) 
    {
        var prop = (MemberExpression)expr.Body;
        OnPropertyChanged(prop.Member.Name);
    }
}

public class MyData : BaseEntity 
{
    private string firstName;

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; OnPropertyChanged(e => FirstName); }
    }

    private string surName;
    public string Surname
    {
        get { return surName; }
        set { surName = value; OnPropertyChanged(e => Surname); }
    }
 }
公共抽象类BaseEntity:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
/// 
///引发PropertyChanged事件
/// 
///物业名称
公共void OnPropertyChanged(字符串propertyName)
{
var ev=改变的财产;
如果(ev!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
/// 
///引发PropertyChanged事件
/// 
///标识已更新属性的Lambda表达式
公共void OnPropertyChanged(表达式表达式)
{
var prop=(MemberExpression)expr.Body;
OnPropertyChanged(prop.Member.Name);
}
}
公共类MyData:BaseEntity
{
私有字符串名;
公共字符串名
{
获取{return firstName;}
设置{firstName=value;OnPropertyChanged(e=>firstName);}
}
私家姓;
公共字符串姓氏
{
获取{返回姓氏;}
集合{姓氏=值;OnPropertyChanged(e=>姓氏);}
}
}

Class MyData必须实现INotifyPropertyChanged接口,并在FirstName属性更改时引发PropertyChanged事件。ObservableCollection在这里没有帮助,因为集合没有更改。@Clemens感谢您的回复。我读过很多关于INotifyPropertyChanged和引发PropertyChanged事件的文章,但所有的努力都没有奏效。我想是执行问题。你能告诉我如何在这个项目中成功地做到这一点吗?是的,这似乎成功了,它需要为其他奋斗者添加一个“使用System.ComponentModel”。还需要@gregstoll的评论。I.E Mode=单向添加到XAML中的所有x:Bind语句。谢谢。这里可以提出补充问题吗?我注意到ItemsControl仅在StartButton_Click事件处理程序(以及程序)完成后更新。我确实需要随着每个属性的更改而更改视图,即在RowItems[0]更改后立即更改视图;在事件处理程序返回之前执行。这可能吗?@gaw最好问新问题,避免问题混淆,保持清晰topic@gaw您在更改属性后是否正在执行耗时的操作?正如建议的那样,我在此处将其作为另一个问题提出>,它还具有与上面原始答案相同的更正代码。我发现这一个错误。找不到BaseDataContract??抱歉,只是我的代码中有一个小故障(它是从我的一个项目改编的)。请现在检查。我仍然得到一个错误,但这次“BaseEntity不包含FirstName…”的定义(来自e.FirstName)和e.LastName的定义相同?我终于有时间正确地测试它了。是的,OnPropertyChanged调用应该提供item=>Property,因为提供了来自实际类的属性,而不是来自BaseEntity的属性。这样更好。工作完美。谢谢你的努力!同样为了其他人的利益,这需要“使用System.ComponentModel;”补充。
<TextBlock Text="{x:Bind FirstName, Mode=OneWay}" Margin="10,0,5,0"/>
<TextBlock Text="{x:Bind Surname, Mode=OneWay}"/>
 private void Button_Click(object sender, RoutedEventArgs e)
    {
        coll[0].FirstName = "Bill";
        Task.Run(()=> {
               Thread.Sleep(5000);
               MessageBox.Show("");
                       });
    }  
public abstract class BaseEntity : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises the PropertyChanged event
    /// </summary>
    /// <param name="propertyName">Name of the property</param>
    public void OnPropertyChanged(string propertyName)
    {
        var ev = PropertyChanged;
        if (ev != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// Raises the PropertyChanged event
    /// </summary>
    /// <param name="expr">Lambda expression that identifies the updated property</param>
    public void OnPropertyChanged<TProp>(Expression<Func<BaseEntity, TProp>> expr) 
    {
        var prop = (MemberExpression)expr.Body;
        OnPropertyChanged(prop.Member.Name);
    }
}

public class MyData : BaseEntity 
{
    private string firstName;

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; OnPropertyChanged(e => FirstName); }
    }

    private string surName;
    public string Surname
    {
        get { return surName; }
        set { surName = value; OnPropertyChanged(e => Surname); }
    }
 }