I have ComboBox with CheckBoxes for items. When user checks or uncheckes boxes I want the selected values to be displayed in the ContentPresenter separated by comma. At the the moment I have overridden C开发者_StackOverflowontentPresenter:
<ContentPresenter x:Name="ContentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ContentTemplate="{StaticResource SelectedOperationsText}"/>
ContentPresenter is a part of ComboBox style by default. Any hints on how to implement this feature?
ComboBox ItemTemplate is implemented like this:
<DataTemplate x:Key="ComboItemTemplate">
<Grid HorizontalAlignment="Left">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Text}"/>
</Grid>
</DataTemplate>
This solution isn't ideal (for example, you can create custom control template for control inherited from combobox), but it works.
Xaml
<my:MyComboBox Width="180" ItemsSource="{Binding TestItems}" Text="{Binding SelectedItemsText}"> <my:MyComboBox.ItemTemplate> <DataTemplate> <Grid HorizontalAlignment="Left"> <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Text}"/> </Grid> </DataTemplate> </my:MyComboBox.ItemTemplate> </my:MyComboBox>
Hack of the combobox:
public class MyComboBox : ComboBox { private ContentPresenter selectedContent; public MyComboBox() { this.DefaultStyleKey = typeof(ComboBox); } public override void OnApplyTemplate() { this.selectedContent = this.GetTemplateChild("ContentPresenter") as ContentPresenter; this.RefreshContent(); base.OnApplyTemplate(); this.SelectionChanged += (s, e) => { //Cancel selection this.SelectedItem = null; this.RefreshContent(); }; } public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(MyComboBox), new PropertyMetadata(null, new PropertyChangedCallback((s,e)=>((MyComboBox)s).RefreshContent()))); private void RefreshContent() { if (this.selectedContent != null) { var tb = (TextBlock)this.selectedContent.Content; tb.Text = this.Text; } } }
MainViewModel
public class MainViewModel : INotifyPropertyChanged { public MainViewModel() { this.InitializeTestItems(); } public void InitializeTestItems() { this.TestItems = new List<TestItemModel>{ new TestItemModel{IsChecked=true, Text="first"}, new TestItemModel{IsChecked=false, Text="second"}, new TestItemModel{IsChecked=false, Text="third"}}; this.RefreshSelectedItemsText(); foreach (var item in this.TestItems) item.CheckChanged += (s, e) => this.RefreshSelectedItemsText(); } private void RefreshSelectedItemsText() { SelectedItemsText = string.Join(", ", this.TestItems.Where(ti => ti.IsChecked).Select(ti => ti.Text)); } public List<TestItemModel> TestItems { get; set; } private string selectedItemsText; public string SelectedItemsText { get { return selectedItemsText; } set { selectedItemsText = value; OnPropertyChanged("SelectedItemsText"); } } }
4.ItemViewModel
public class TestItemModel
{
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (CheckChanged != null)
CheckChanged(this, null);
}
}
public string Text { get; set; }
public event EventHandler<EventArgs> CheckChanged;
}
I did not understand what you meant by "the ContentPresenter".
If you want a combox box, with the list of selected items as its text, I can explain how my son (who's not in SO) did it:
He put a grid with a ComboBox followed by a TextBlock. The ItemTemplate of the ComboBox includes a check box with a handler for the Checked and UnChecked events. In these events, he recomputed the Text property of the TextBlock, based on the selected state of the check boxes. Here is the XAML:
<Grid Name="LayoutRoot">
<ComboBox ItemsSource="{Binding Path=SitesList}" Name="CBsites" DropDownOpened="ComboBox_DropDownOpened" DropDownClosed="ComboBox_DropDownClosed">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Path=Location}" Checked="SiteCheckBox_Checked" Unchecked="SiteCheckBox_Unchecked" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Name="TXTselected" IsHitTestVisible="False" VerticalAlignment="Center" Margin="6,0,0,0" />
</Grid>
I think one can do it without the TextBlock. Hopefully, this can put you in the right direction.
I have created a codeplex project here: codeplex inspired by this blog and a number other ones, please check it out and improve it etc. Hopefully this or something like it will find it's way into the toolkit...
I prefer not needing a selection boolean in the bound data so i brought a bindable SelectedItems
精彩评论