Silverlight依赖属性未在自定义控件中通知

时间:2015-10-09 13:32:28

标签: c# wpf xaml silverlight mvvm

方案

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

enter image description here

我通过继承文本Box控件创建了一个自定义Label,我在其中执行了Dependency属性的回调事件中的所有更改。 (检查自定义文本框代码)

现在的问题是,当我更改View模型中的有界属性时,自定义文本框控件中的回调事件没有触发(我通过在复选框后面的代码中向observable集合添加值来执行此操作)检查事件。请选中复选框事件代码。)

我可以看到,第一次在视图模型中加载默认数据时,该行被 “Getter” 部分中的断点点击“SelectedFilterResources” 。但我从未在该物业的Setter部分受到打击。

自定义文本框

自定义文本框包含 “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 + "...";
                        }
                    }
                }
            }
        }
    }

自定义组合框。

这是我使用上述自定义标签的控件。这也是一个自定义控件,因此此控件中的大多数属性和样式都是自定义的。 “DPItemSlectionBoxTemplate” 是一个依赖项属性,我通过向控件模板添加附加属性来启用组合框的选择框。这个控件工作正常,因为我在系统的其他地方使用这个控件用于不同的目的。

                    <styles:CommonMultiComboBox 
                                x:Name="Resourcescmb" IsEnabled="{Binding IsResourceComboEnable,Mode=TwoWay}" 
                                IsTabStop="False" 
                                >

                        <styles:CommonMultiComboBox.ItemDataTemplate>
                            <DataTemplate>
                                <CheckBox   IsChecked="{Binding IsSelect, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Click="CheckBox_Click" 
                                            Content="{Binding ResourceCaption}"
                                            Style="{StaticResource CommonCheckBoxStyle}"
                                            Tag ="{Binding}"
                                            Checked="Resource_ToggleButton_OnChecked" />
                            </DataTemplate>
                        </styles:CommonMultiComboBox.ItemDataTemplate>

                        <styles:CommonMultiComboBox.DPItemSlectionBoxTemplate>
                            <DataTemplate>
                                <filtersTemplate:ResourceSelectionBoxLable 
                                    Padding="0"
                                    Height="15"
                                    FontSize="10"
                                    SelectedFilterdResources="{Binding DataContext.FilterdResources,ElementName=root ,Mode=TwoWay}" />

                            </DataTemplate>
                        </styles:CommonMultiComboBox.DPItemSlectionBoxTemplate>
                    </styles:CommonMultiComboBox>

视图模型

private ObservableCollection<ResourceItem> _resourceItems;
        public ObservableCollection<ResourceItem> FilterdResources
        {
            get { return _resourceItems; }
            set
            {
                SetOnChanged(value, ref _resourceItems, "FilterdResources");
            }
        }

视图模型的构造函数

FilterdResources=new ObservableCollection<ResourceItem>();

“SetOnChanged” 是View Model基类中的一个方法,我们有一个INotifyPropertichanged实现。

复选框事件

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);

            }
}

我可以通过View Model Property从代码中访问View Model。

为什么在更改有界值时不会通知回叫事件?我错过了什么吗?依赖属性应该适用于双向绑定不是吗?有人可以帮我这个吗?

提前致谢。

1 个答案:

答案 0 :(得分:1)

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

您需要做的是在setter中订阅 ObservableCollection CollectionChanged 事件或更改回调(您已经拥有 - 您的依赖项属性的CaptionCollectionChanged

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.
    }

不要忘记添加清理逻辑 - 在更改集合实例时取消订阅集合更改等等。