开发者

Combobox display value in Silverlight

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.

  1. 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>
    
  2. 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;
        }
    }
    }
    
  3. 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜