C# ItemsControl在数据更改为ObservableCollection后不更新<;T>;财产
我有以下测试代码… XAML: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
代码隐藏:
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); }
}
}