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

标签 c# wpf xaml silverlight mvvm

场景

我有一个自定义组合框,在组合框选择框中有一个标签。我需要按照第二张图片中的说明更改标签。但我只想在通过选中复选框来选择项目时执行此操作。我可以选择多个项目,因此标签应更新为所选项目的逗号分隔值。如果没有足够的空间来显示标签的全文,应该有 "..." 符号来表示在组合框中选择了更多的项目。

enter image description here

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

现在的问题是,当我更改 View 模型中的边界属性时,自定义文本框控件中的回调事件没有触发(我这样做是通过在复选框后面的代码中向可观察集合添加值来实现的)检查事件。请检查复选框事件代码)。

我可以看到,当我第一次在 View 模型中加载默认数据时,该行被 “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>

View 模型

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

View 模型的构造函数

FilterdResources=new ObservableCollection<ResourceItem>();

“SetOnChanged” 是 View 模型基类中的一个方法,我们在其中实现了 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 模型属性从代码隐藏访问 View 模型。

为什么当我更改有界值时没有通知回调事件?我在这里错过了什么吗?依赖属性应该适用于双向绑定(bind),不是吗?有人可以帮我解决这个问题吗?

提前致谢。

最佳答案

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

您在这里需要做的是在 setter 或更改回调(您已经拥有 - 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.
    }

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

关于c# - Silverlight 依赖属性未在自定义控件中通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33039633/

相关文章:

c# - 翻译 DataGrid MouseEvent 所以我在 View 的代码隐藏中没有代码

c# - Wpf,未应用样式

c# - UserControl InputBindings 仅在先按下按钮后工作

c# - 从角度A移动到B,找到最短的方向

c# - 如何使用 C# 从 Windows 服务运行 EXE 程序?

c# - 给定一个整数数组。找到具有最大总和的最大子数组

c# - 如何防止组合框选择更改事件的重复方法?

c# - 在后面创建数据模板代码

wpf - 如何在 WPF 中将 ItemsSource 的索引作为 CommandParameter 传递

c# - 从路径字符串或 FileInfo 获取驱动器号