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 绑定属性更改后未更新Treeview复选框(SL4)_Silverlight_Checkbox_Treeview - Fatal编程技术网

Silverlight 绑定属性更改后未更新Treeview复选框(SL4)

Silverlight 绑定属性更改后未更新Treeview复选框(SL4),silverlight,checkbox,treeview,Silverlight,Checkbox,Treeview,我的问题很简单。我有一个树状视图绑定到一个对象的可观察集合,这些对象都有自己的可观察集合。根据用户在我的页面上选择的其他条件,我希望动态设置选中的复选框不幸的是,在我更改绑定到IsChecked的相应bool属性后,我的复选框无法更新其IsChecked状态。第一次展开任何节点时,复选框将处于正确状态,但之后它们将停止更新。我怀疑这意味着在第一次实际显示对象之前,不会创建/评估对象 数据结构为Silverlight->ViewModel->ObservableCollection of Stor

我的问题很简单。我有一个树状视图绑定到一个对象的可观察集合,这些对象都有自己的可观察集合。根据用户在我的页面上选择的其他条件,我希望动态设置选中的复选框不幸的是,在我更改绑定到IsChecked的相应bool属性后,我的复选框无法更新其IsChecked状态。第一次展开任何节点时,复选框将处于正确状态,但之后它们将停止更新。我怀疑这意味着在第一次实际显示对象之前,不会创建/评估对象

数据结构为Silverlight->ViewModel->ObservableCollection of StoreGroups LocalStoreGroups->StoreGroup has ObservableCollection of Store Stores

通过调试,我注意到没有附加到this.PropertyChanged的处理程序,我想知道这是否是问题所在

Treeview控件:

<controls:TreeView ItemsSource="{Binding LocalStoreGroups}" ItemTemplate="{StaticResource TreeviewStoreGroupTemplate}" />
选择更改代码

 foreach (Store s in LocalStoreGroups.SelectMany(sg => sg.Stores))
        {
            s.IsSelected = false;
        }

        foreach (StoreLink link in links)
        {
            Store targetStore = (from s in LocalStoreGroups.SelectMany(sg => sg.Stores) where s.DTO.ID == link.DTO.StoreID select s).FirstOrDefault();
            targetStore.IsSelected = true;
        }

看起来您正在更新属性以响应加载事件。更新属性时,很可能您不在UI线程上。除非在UI线程上发生更改,否则不会更新显示

对于绑定属性和集合属性(而不是可观察集合中的子级),只有OnPropertyChanged需要位于UI线程上。属性可以提前更改,但在调用OnPropertyChanged之前,UI不会更改绑定

我们所有的ViewModels都源自我们创建的ViewModelBase,它实现了一个帮助器SendPropertyChanged,如下所示(因此我们永远不必担心跨线程)

我们所有的notify属性都调用它,而不是直接调用OnPropertyChanged

它还公开了一个通常有用的OnUiThread方法,以便您可以在UI线程上执行任意代码:

protected delegate void OnUiThreadDelegate();

public event PropertyChangedEventHandler PropertyChanged;

public void SendPropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
    {
        this.OnUiThread(() => this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
    }
}

protected void OnUiThread(OnUiThreadDelegate onUiThreadDelegate)
{
    if (Deployment.Current.Dispatcher.CheckAccess())
    {
        onUiThreadDelegate();
    }
    else
    {
        Deployment.Current.Dispatcher.BeginInvoke(onUiThreadDelegate);
    }
}

无论如何,这里的泄露应该是没有人订阅PropertyChanged事件。事实证明,尽管我实现了PropertyChanged事件,但我忘记了实际为类提供INotifyPropertyChanged接口

设置该值时,是否在后台线程中发生此情况?否,在UI线程上使用以下方法调用底部的代码(要更改的代码为Selected):来自Mvvmlight的DispatcherHelper.CheckBeginInvokeOnUI(…)。我想知道
OnPropertyChanged
方法如何工作,因为它不接受字符串,虽然您向它传递一个字符串,但在这两者之间有一个我没有复制的方法,该方法创建了参数,然后将它们传递给我复制的参数。无论如何,这里给出的信息应该是没有人订阅PropertyChanged事件。事实证明,尽管我实现了PropertyChanged事件,但我忘记了实际为类提供INotifyPropertyChanged接口。通过在visual studio中使用断点进行调查,我可以确认在主线程上调用了更新代码。此外,我正在使用MVVMLight框架,它确实提供了一种方法来实现您的建议(尽管您的解决方案看起来更整洁)。最后,属性更改事件将永远不会在试图发出更改信号的对象上引发,因为this.PropertyChanged=null。这可能是因为它是可观察集合中某个对象的子对象吗?
 foreach (Store s in LocalStoreGroups.SelectMany(sg => sg.Stores))
        {
            s.IsSelected = false;
        }

        foreach (StoreLink link in links)
        {
            Store targetStore = (from s in LocalStoreGroups.SelectMany(sg => sg.Stores) where s.DTO.ID == link.DTO.StoreID select s).FirstOrDefault();
            targetStore.IsSelected = true;
        }
protected delegate void OnUiThreadDelegate();

public event PropertyChangedEventHandler PropertyChanged;

public void SendPropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
    {
        this.OnUiThread(() => this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
    }
}

protected void OnUiThread(OnUiThreadDelegate onUiThreadDelegate)
{
    if (Deployment.Current.Dispatcher.CheckAccess())
    {
        onUiThreadDelegate();
    }
    else
    {
        Deployment.Current.Dispatcher.BeginInvoke(onUiThreadDelegate);
    }
}