Silverlight 如何在SL4中的索引子级上实现INotifyPropertyChanged?
我的ViewModel类有一个“Messages”类型的子属性,它有一个索引属性,如:Silverlight 如何在SL4中的索引子级上实现INotifyPropertyChanged?,silverlight,data-binding,silverlight-4.0,Silverlight,Data Binding,Silverlight 4.0,我的ViewModel类有一个“Messages”类型的子属性,它有一个索引属性,如: public class ViewModel { // ... public Messages Messages { get { if (_messages == null) { LoadMessagesAsync(); _messages =
public class ViewModel
{
// ...
public Messages Messages
{
get
{
if (_messages == null)
{
LoadMessagesAsync();
_messages = new Messages();
}
return _messages;
}
set
{
_messages = values;
PropertyChanged(new PropertyChangedArgs("Messages");
}
}
// ...
private void LoadMessagesAsync()
{
// Do the service call
Messages = theResult;
}
}
public class Messages
{
// ...
public String this[String name]
{
get { return _innerDictionary[name]; }
}
// ...
}
我不认为我需要填补其余的空白,因为这都是直截了当的
我遇到的问题是,当我将Messages属性设置为新对象时,绑定没有更新。以下是我如何在XAML中引用属性(以ViewModel作为DataContext):
我的假设是,当为“Messages”属性引发PropertyChanged事件时,绑定将更新
我在其他地方读到,我的Messages类应该引发一个PropertyChanged事件,属性名为空字符串(“”),“Item[]”或“Item[“+name+”]”。但是,由于我正在完全替换Messages对象,因此这不会起作用,因为我从未实际更改过内容
我该怎么做
更新
因此,我对行为和BCL源代码进行了一些深入研究,以了解如何使代码正常工作。我学到了两个方面:
首先,Silverlight数据绑定实际上是将Messages属性中的返回对象视为绑定的源。因此,从ViewModel(发送方是ViewModel)提升PropertyChanged不由绑定处理。实际上,我必须从Messages类引发事件
这与使用以下命令没有什么不同:Text={Binding Messages.HelloWorld}”
Myles的代码工作的原因是“Data”返回“this”,因此绑定被愚弄到将父类视为绑定源
也就是说,即使我使其使我的子对象引发事件,它仍然无法工作。这是因为绑定使用System.Windows.IndexerListener作为绑定目标。在SourcePropertyChanged方法中,侦听器检查属性名称是否为“Item[]“但不采取行动。下一条语句委托给PropertyListener,后者检查属性名称,并且仅当它等于“Item[HelloWorld]”时才处理事件
因此,除非我为集合中的每个可能值显式引发事件,否则UI将永远不会更新。这是令人失望的,因为其他文章和帖子表明“Item[]”应该有效,但查看源代码就证明了这一点
尽管如此,我仍然希望有办法实现我的目标。好的,这里的根本问题是绑定没有指定的路径,因此,绑定框架不知道在处理PropertyChanged事件时要查找哪个属性名。因此,我为绑定创建了一个路径,以便更改通知能够工作 我编写了以下代码,证明当实际的底层字典发生更改时,索引器绑定会被刷新: 视图模型
public class BindingTestViewModel : AppViewModelBase, IBindingTestViewModel
{
private Dictionary<string, object> _data = new Dictionary<string, object>();
public BindingTestViewModel()
{
_data.Add("test","1");
_data.Add("test2", "21");
}
public object this[string index]
{
get
{
return _data[index];
}
set
{
_data[index] = value;
NotifyOfPropertyChange(() => Data);
}
}
public object Data
{
get
{
return this;
}
}
public void Refresh()
{
_data = new Dictionary<string, object>
{
{"test", "2"}, {"test2", "22"}
};
NotifyOfPropertyChange(() => Data);
}
}
好,这里的根本问题是绑定没有指定路径,因此,绑定框架不知道在处理PropertyChanged事件时要查找哪个属性名。因此,我为绑定创建了一个路径,以便更改通知能够工作 我编写了以下代码,证明当实际的底层字典发生更改时,索引器绑定会被刷新: 视图模型
public class BindingTestViewModel : AppViewModelBase, IBindingTestViewModel
{
private Dictionary<string, object> _data = new Dictionary<string, object>();
public BindingTestViewModel()
{
_data.Add("test","1");
_data.Add("test2", "21");
}
public object this[string index]
{
get
{
return _data[index];
}
set
{
_data[index] = value;
NotifyOfPropertyChange(() => Data);
}
}
public object Data
{
get
{
return this;
}
}
public void Refresh()
{
_data = new Dictionary<string, object>
{
{"test", "2"}, {"test2", "22"}
};
NotifyOfPropertyChange(() => Data);
}
}
我不一定喜欢回答自己的问题,但我已经找到了解决问题的办法。我已经能够保持我原来的流程并解决SL4数据绑定的特性。代码看起来也有点干净 归根结底,我不再替换子对象。这似乎是关键。相反,我创建了一个实例,并让该实例根据需要管理更改项目的内部列表。子对象在发生更改时通知父对象,以便父对象可以引发PropertyChanged事件。以下是我如何使其工作的一个简单示例:
public class ViewModel
{
// ...
public Messages Messages
{
get
{
if (_messages == null)
{
lock (_messagesLock)
{
if (_messages == null)
{
_messages = new Messages();
_messages.ListChanged += (s, e) =>
{
NotifyPropertyChanged("Messages");
};
}
}
}
return _messages;
}
}
}
public class Messages
{
// ...
public String this[String name]
{
get
{
if (_innerDictionary == null)
{
_innerDictionary = new Dictionary<String, String>();
LoadMessagesAsync();
}
return _innerDictionary[name];
}
}
// ...
private void LoadMessagesAsync()
{
// Do the service call
_innerDictionary = theResult;
NotifyListChanged();
}
// ...
public event EventHandler ListChanged;
}
公共类视图模型
{
// ...
公共信息
{
得到
{
如果(_messages==null)
{
锁定(_messagesLock)
{
如果(_messages==null)
{
_消息=新消息();
_messages.ListChanged+=(s,e)=>
{
NotifyPropertyChanged(“消息”);
};
}
}
}
返回消息;
}
}
}
公共类消息
{
// ...
公共字符串此[字符串名称]
{
得到
{
如果(_innerDictionary==null)
{
_innerDictionary=新字典();
LoadMessagesAsync();
}
返回_innerDictionary[名称];
}
}
// ...
私有void LoadMessagesAsync()
{
//打服务电话吗
_innerDictionary=结果;
NotifyListChanged();
}
// ...
公共事件事件处理程序列表已更改;
}
为了简单起见,我省略了显而易见的部分。我不一定喜欢回答自己的问题,但我已经找到了解决问题的方法。我已经能够保持我原来的流程并解决SL4数据绑定的特性。代码看起来也有点干净 归根结底,我不再替换子对象。这似乎是关键。相反,我创建了一个实例,并让该实例根据需要管理更改项目的内部列表。子对象在发生更改时通知父对象,以便父对象可以引发PropertyChanged事件。以下是我如何使其工作的一个简单示例:
public class ViewModel
{
// ...
public Messages Messages
{
get
{
if (_messages == null)
{
lock (_messagesLock)
{
if (_messages == null)
{
_messages = new Messages();
_messages.ListChanged += (s, e) =>
{
NotifyPropertyChanged("Messages");
};
}
}
}
return _messages;
}
}
}
public class Messages
{
// ...
public String this[String name]
{
get
{
if (_innerDictionary == null)
{
_innerDictionary = new Dictionary<String, String>();
LoadMessagesAsync();
}
return _innerDictionary[name];
}
}
// ...
private void LoadMessagesAsync()
{
// Do the service call
_innerDictionary = theResult;
NotifyListChanged();
}
// ...
public event EventHandler ListChanged;
}
公共类视图模型
{
// ...
公共信息
{
得到
{
如果(_messages==null)
{
锁定(_messagesLock)
{
public class ViewModel
{
// ...
public Messages Messages
{
get
{
if (_messages == null)
{
lock (_messagesLock)
{
if (_messages == null)
{
_messages = new Messages();
_messages.ListChanged += (s, e) =>
{
NotifyPropertyChanged("Messages");
};
}
}
}
return _messages;
}
}
}
public class Messages
{
// ...
public String this[String name]
{
get
{
if (_innerDictionary == null)
{
_innerDictionary = new Dictionary<String, String>();
LoadMessagesAsync();
}
return _innerDictionary[name];
}
}
// ...
private void LoadMessagesAsync()
{
// Do the service call
_innerDictionary = theResult;
NotifyListChanged();
}
// ...
public event EventHandler ListChanged;
}