Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Silverlight 如何在SL4中的索引子级上实现INotifyPropertyChanged?_Silverlight_Data Binding_Silverlight 4.0 - Fatal编程技术网

Silverlight 如何在SL4中的索引子级上实现INotifyPropertyChanged?

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 =

我的ViewModel类有一个“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;
}