方案
我有一个自定义组合框,我在Combobox选择框中有一个标签。我需要更改标签,如我在第二张图片中所述。但我只想在选中项目时选中复选框。我可以选择多个项目,因此标签应该更新为所选项目的逗号分隔值。如果没有足够的空间显示标签的全文,则应该有“...”符号表示在组合框中选择了更多项目。
我通过继承文本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。
为什么在更改有界值时不会通知回叫事件?我错过了什么吗?依赖属性应该适用于双向绑定不是吗?有人可以帮我这个吗?
提前致谢。
答案 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.
}
不要忘记添加清理逻辑 - 在更改集合实例时取消订阅集合更改等等。