C# 自定义控件中的Silverlight Dependency属性未发出通知

C# 自定义控件中的Silverlight Dependency属性未发出通知,c#,wpf,xaml,silverlight,mvvm,C#,Wpf,Xaml,Silverlight,Mvvm,场景 我有一个自定义组合框,其中组合框选择框中有一个标签。我需要更改标签,如我在第二张图中所述。但我只想在通过选中复选框选择项目时执行此操作。我可以选择多个项目,因此标签应更新为所选项目的逗号分隔值。如果没有足够的空间显示标签的全文,则应显示“…”符号,以指示组合框中选择了更多项目 我通过继承文本框控件创建了一个自定义标签,在该控件中我对依赖项属性的回调事件进行了所有更改。(选中自定义文本框代码) 现在的问题是,当我更改视图模型中的bounded属性时,自定义文本框控件中的回调事件没有触发(我

场景

我有一个自定义组合框,其中组合框选择框中有一个标签。我需要更改标签,如我在第二张图中所述。但我只想在通过选中复选框选择项目时执行此操作。我可以选择多个项目,因此标签应更新为所选项目的逗号分隔值。如果没有足够的空间显示标签的全文,则应显示“…”符号,以指示组合框中选择了更多项目

我通过继承文本框控件创建了一个自定义标签,在该控件中我对依赖项属性的回调事件进行了所有更改。(选中自定义文本框代码)

现在的问题是,当我更改视图模型中的bounded属性时,自定义文本框控件中的回调事件没有触发(我是通过在check event上的code behind in复选框中将值添加到observable集合中来实现的。请选中复选框事件代码)

我可以看到,当我第一次在视图模型中加载默认数据时,该行被“Getter”部分“SelectedFilterResources”中的断点击中。但我从来没有在酒店的二传部分得到过成功

public static readonly DependencyProperty FilterdResourcesProperty =
        DependencyProperty.Register("SelectedFilterdResources",
            typeof (ObservableCollection<ResourceItem>),
            typeof (ResourceSelectionBoxLable),
            new PropertyMetadata(new ObservableCollection<ResourceItem>(),
                CaptionCollectionChanged));


private static void CaptionCollectionChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        var collection = args.NewValue as INotifyCollectionChanged;
        if (collection != null)
        {
            var sender = d as ResourceSelectionBoxLable;
            if (sender != null)
            {
                collection.CollectionChanged += sender.BoundItems_CollectionChanged;
            }                
        }
    }

    private void BoundItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // Do your control logic here.
    }
自定义文本框

自定义文本框具有“CaptionCollectionChanged”回调事件。在这里,我拥有实现我的场景的所有逻辑“资源项”这里是一种模型

    public class ResourceSelectionBoxLable : TextBox
    {
        public override void OnApplyTemplate()
        {
         base.OnApplyTemplate();
        IsReadOnly = true;
        }


        public static List<ResourceItem> LocalFilterdResources = new List<ResourceItem>();

        #region Dependancy Properties

        public static readonly DependencyProperty FilterdResourcesProperty =
            DependencyProperty.Register("SelectedFilterdResources",
                typeof (ObservableCollection<ResourceItem>),
                typeof (ResourceSelectionBoxLable),
                new PropertyMetadata(new ObservableCollection<ResourceItem>(),
                    CaptionCollectionChanged));

        public ObservableCollection<ResourceItem> SelectedFilterdResources
        {
            get
            {
                return
                (ObservableCollection<ResourceItem>) GetValue(FilterdResourcesProperty);
            }
            set
            {
                SetValue(FilterdResourcesProperty, value);
                LocalFilterdResources = new List<ResourceItem>(SelectedFilterdResources);
            }
        }

        #endregion

        private static void CaptionCollectionChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var resourceSelectionBoxLable = d as ResourceSelectionBoxLable;
            if (resourceSelectionBoxLable != null)
            {
                if (LocalFilterdResources.Count <= 0)
                {
                    resourceSelectionBoxLable.Text = "Resources"
                }
                else
                {
                    var actualwidthOflable = resourceSelectionBoxLable.ActualWidth;
                    var newValue = e.NewValue as string;

                    //Get the Wdith of the Text in Lable
                    TextBlock txtMeasure = new TextBlock();
                    txtMeasure.FontSize = resourceSelectionBoxLable.FontSize;
                    txtMeasure.Text = newValue;
                    double textwidth = txtMeasure.ActualWidth;

                    //True if Text reach the Limit
                    if (textwidth > actualwidthOflable)
                    {
                        var appendedString = string.Join(", ",
                            LocalFilterdResources.Select(item => item.ResourceCaption)
                                .ToArray());
                        resourceSelectionBoxLable.Text = appendedString;
                    }
                    else
                    {
                        if (LocalFilterdResources != null)
                        {
                            var morestring = string.Join(", ",
                                (LocalFilterdResources as IEnumerable<ResourceItem>).Select(item => item.ResourceCaption)
                                    .ToArray());

                            var subsring = morestring.Substring(0, Convert.ToInt32(actualwidthOflable) - 4);
                            resourceSelectionBoxLable.Text = subsring + "...";
                        }
                    }
                }
            }
        }
    }
我可以通过视图模型属性从代码隐藏中访问视图模型

为什么在我更改有界值时不通知回调事件?我是不是遗漏了什么?依赖属性应该适用于双向绑定,不是吗?谁能帮我一下吗


提前感谢。

看起来您的问题在于,当绑定集合发生更改(即添加或删除项目)时,您希望触发CaptionCollectionChanged事件。实际上,只有在更改绑定对象的实例时,才会触发此事件

这里您需要做的是在setter或更改依赖项属性的callback(您已经更改了)中订阅ObservableCollectionCollectionChanged事件

public static readonly DependencyProperty FilterdResourcesProperty =
        DependencyProperty.Register("SelectedFilterdResources",
            typeof (ObservableCollection<ResourceItem>),
            typeof (ResourceSelectionBoxLable),
            new PropertyMetadata(new ObservableCollection<ResourceItem>(),
                CaptionCollectionChanged));


private static void CaptionCollectionChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        var collection = args.NewValue as INotifyCollectionChanged;
        if (collection != null)
        {
            var sender = d as ResourceSelectionBoxLable;
            if (sender != null)
            {
                collection.CollectionChanged += sender.BoundItems_CollectionChanged;
            }                
        }
    }

    private void BoundItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // Do your control logic here.
    }
公共静态只读从属属性筛选器资源属性=
DependencyProperty.Register(“SelectedFilterResources”,
类型(可观测采集),
类型(ResourceSelectionBoxLable),
新的PropertyMetadata(新的ObservableCollection(),
CaptionCollectionChanged);
私有静态void CaptionCollectionChanged(DependencyObject d,
DependencyPropertyChangedEventArgs(参数)
{
var collection=args.NewValue作为INotifyCollectionChanged;
if(集合!=null)
{
var sender=d作为ResourceSelectionBoxLable;
if(发送方!=null)
{
collection.CollectionChanged+=sender.BoundItems\u CollectionChanged;
}                
}
}
私有void BoundItems\u CollectionChanged(对象发送方,NotifyCollectionChangedEventArgs e)
{
//在这里执行控制逻辑。
}

别忘了添加清理逻辑-更改集合实例时取消订阅集合更改等等。

我注意到一些问题可能会在某一天影响到你,我想告诉你:1。为“SelectedFilterResources”[sic]依赖项属性设置dafault值的方法是创建一个意外的单例。2.我将坚持将依赖项属性命名为与静态DP backingfield完全相同的约定。3.不要将代码放在DP的setter中,绑定引擎不会调用它,请改用propertyChangedCallback。@Martin.Thank。是的,我把代码从Setter移到了callback事件。你能解释一下SelectedFilterResources是如何意外创建Singleton的吗?静态backingfield只允许静态内容(对所有实例来说都是相同的)与之关联。因此,作为默认值创建的集合实例在所有实例之间共享,因此是一个单实例。改用构造函数,您可以将新创建的集合实例指定为DP的默认值。@Martin.Thank。我把它移到构造函数中:)。谢谢。现在我可以在更改有界列表时收到通知。
FilterdResources=new ObservableCollection<ResourceItem>();
private void Resource_ToggleButton_OnChecked(object sender, RoutedEventArgs e)
        {

            var  senderControl = sender as CheckBox;
            if(senderControl==null)
                return;

            var selectedContent=senderControl.Tag as ResourceItem;

            if (selectedContent != null)
            {
                    ViewModel.FilterdResources.Add(selectedContent);

            }
}
public static readonly DependencyProperty FilterdResourcesProperty =
        DependencyProperty.Register("SelectedFilterdResources",
            typeof (ObservableCollection<ResourceItem>),
            typeof (ResourceSelectionBoxLable),
            new PropertyMetadata(new ObservableCollection<ResourceItem>(),
                CaptionCollectionChanged));


private static void CaptionCollectionChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        var collection = args.NewValue as INotifyCollectionChanged;
        if (collection != null)
        {
            var sender = d as ResourceSelectionBoxLable;
            if (sender != null)
            {
                collection.CollectionChanged += sender.BoundItems_CollectionChanged;
            }                
        }
    }

    private void BoundItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // Do your control logic here.
    }