Scenario
I have a custom combo box where i have a label in the Combobox selection box. I need to change the label as I noted in the second image. But I want to do it only when I select items by selecting the check box. I can select multiple items, so the label should be updated as a comma separated value of selected items. If there is not enough space to display the full text of the label there should be "..." symbol to indicate that there are more items selected in the combo box.
I created a custom Label by inheriting the text Box control where I do all the changes in the callback event of a Dependency property. (Check custom Text Box code)
Now the problem is that the callback event in the custom Text box control is not firing when I change the bounded property in the View model (I am doing this by adding values to the observable collection in the code behind in check box on Check event. Please Check check box event code).
I can see that first time when I load default data in the view model the line is hit by the break point in the "Getter" part of "SelectedFilterResources" . But I never get a hit in the Setter part of the property.
Custom Text Box
The custom text box has the "CaptionCollectionChanged" callback event. It is the place where I have all logic to achieve my scenario. "Resources item" here is a type of Model.
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 + "...";
}
}
}
}
}
}
Custom Combo Box.
This is the control where I use the above custom label. This is also a custom control so most of the properties and styles in this controls are custom made. "DPItemSlectionBoxTemplate" is a dependency property where I enable the Selection Box of the combo box by adding an attached property to the control template. This control works fine, because I use this control in other places in my system for different purposes.
<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>
ViewModel
private ObservableCollection<ResourceItem> _resourceItems;
public ObservableCollection<ResourceItem> FilterdResources
{
get { return _resourceItems; }
set
{
SetOnChanged(value, ref _resourceItems, "FilterdResources");
}
}
Constructor of View Model
FilterdResources=new ObservableCollection<ResourceItem>();
"SetOnChanged" is a method in the View Model base class where we have the INotifyPropertichanged implementation.
Check Box Event
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);
}
}
I can access the View Model from the Code behind through the View Model Property.
Why is the call back event not notified when I change bounded values? Am i missing something here? Dependency properties are supposed to work for two way bindings aren't they? Could any one please help me on this?
Thanks in advance.
