C# 自定义控件中的Silverlight Dependency属性未发出通知
场景 我有一个自定义组合框,其中组合框选择框中有一个标签。我需要更改标签,如我在第二张图中所述。但我只想在通过选中复选框选择项目时执行此操作。我可以选择多个项目,因此标签应更新为所选项目的逗号分隔值。如果没有足够的空间显示标签的全文,则应显示“…”符号,以指示组合框中选择了更多项目 我通过继承文本框控件创建了一个自定义标签,在该控件中我对依赖项属性的回调事件进行了所有更改。(选中自定义文本框代码) 现在的问题是,当我更改视图模型中的bounded属性时,自定义文本框控件中的回调事件没有触发(我是通过在check event上的code behind in复选框中将值添加到observable集合中来实现的。请选中复选框事件代码) 我可以看到,当我第一次在视图模型中加载默认数据时,该行被“Getter”部分“SelectedFilterResources”中的断点击中。但我从来没有在酒店的二传部分得到过成功C# 自定义控件中的Silverlight Dependency属性未发出通知,c#,wpf,xaml,silverlight,mvvm,C#,Wpf,Xaml,Silverlight,Mvvm,场景 我有一个自定义组合框,其中组合框选择框中有一个标签。我需要更改标签,如我在第二张图中所述。但我只想在通过选中复选框选择项目时执行此操作。我可以选择多个项目,因此标签应更新为所选项目的逗号分隔值。如果没有足够的空间显示标签的全文,则应显示“…”符号,以指示组合框中选择了更多项目 我通过继承文本框控件创建了一个自定义标签,在该控件中我对依赖项属性的回调事件进行了所有更改。(选中自定义文本框代码) 现在的问题是,当我更改视图模型中的bounded属性时,自定义文本框控件中的回调事件没有触发(我
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(您已经更改了)中订阅ObservableCollection的CollectionChanged事件
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.
}