带CheckBoxes的WPF ComboBox显示有关已检查项目的信息?

时间:2015-06-22 19:56:20

标签: c# wpf combobox

我试图制作一个包含复选框作为项目的ComboBox,并根据检查的内容在组合框“关闭”时显示不同的内容。

我试图实现的外观可以在图像中看到。

enter image description here

理想情况下,我不希望用户能够选择顶部的文本(在图像中)。

有一个简单的解决方案吗?我已经看到了一些解决方案,当使用DataTriggers隐藏不同的嵌套控件时,可以显示所有项目时显示更多信息,但这并不是我想要的。

有什么想法吗?

/ Erik

3 个答案:

答案 0 :(得分:7)

以下是使用if(PlayerPrefs.GetFloat("nodeNum") > 0) { //Assemble axis value arrays //X var xString = PlayerPrefs.GetString("xVals"); var xValues = xString.Split(","[0]); //Y var yString = PlayerPrefs.GetString("yVals"); var yValues = yString.Split(","[0]); //Z var zString = PlayerPrefs.GetString("zVals"); var zValues = zString.Split(","[0]); var countNode = 0; var goal = PlayerPrefs.GetFloat("nodeNum"); var nodeVecs = new Array(Vector3.zero); while (countNode != goal) { var curVec = Vector3(float.Parse(xValues[countNode]), float.Parse(yValues[countNode]), float.Parse(zValues[countNode])); nodeVecs.Push(curVec); countNode += 1; } var convNodeVecs : Vector3[] = nodeVecs.ToBuiltin(Vector3) as Vector3[]; for(var nodeVec : Vector3 in convNodeVecs) { Instantiate(nodeObj, nodeVec, Quaternion.identity); } } 实现大部分内容的方法,但文本仍然可以选择(使用自定义文本仅在IsEditable为真时才有效)。由于ComboBox,因此无法修改。

查看

IsReadOnly="true"

<强>视图模型

<ComboBox
    IsEditable="True"
    IsReadOnly="True"
    ItemsSource="{Binding Items}"
    Text="{Binding Text}">
    <ComboBox.ItemTemplate>
        <DataTemplate
            DataType="{x:Type local:Item}">
            <CheckBox
                Content="{Binding Name}"
                IsChecked="{Binding IsChecked}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

如果可选文本存在问题,您可能需要创建自定义ComboBox控件模板(默认示例here)。或者,您可以使用其他内容而不是// ObservableObject is a custom base class that implements INotifyPropertyChanged internal class MainWindowVM : ObservableObject { private ObservableCollection<Item> mItems; private HashSet<Item> mCheckedItems; public IEnumerable<Item> Items { get { return mItems; } } public string Text { get { return _text; } set { Set(ref _text, value); } } private string _text; public MainWindowVM() { mItems = new ObservableCollection<Item>(); mCheckedItems = new HashSet<Item>(); mItems.CollectionChanged += Items_CollectionChanged; // Adding test data for (int i = 0; i < 10; ++i) { mItems.Add(new Item(string.Format("Item {0}", i.ToString("00")))); } } private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (Item item in e.OldItems) { item.PropertyChanged -= Item_PropertyChanged; mCheckedItems.Remove(item); } } if (e.NewItems != null) { foreach (Item item in e.NewItems) { item.PropertyChanged += Item_PropertyChanged; if (item.IsChecked) mCheckedItems.Add(item); } } UpdateText(); } private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "IsChecked") { Item item = (Item)sender; if (item.IsChecked) { mCheckedItems.Add(item); } else { mCheckedItems.Remove(item); } UpdateText(); } } private void UpdateText() { switch (mCheckedItems.Count) { case 0: Text = "<none>"; break; case 1: Text = mCheckedItems.First().Name; break; default: Text = "<multiple>"; break; } } } // Test item class // Test item class internal class Item : ObservableObject { public string Name { get; private set; } public bool IsChecked { get { return _isChecked; } set { Set(ref _isChecked, value); } } private bool _isChecked; public Item(string name) { Name = name; } public override string ToString() { return Name; } } ,并使其看起来像ComboBox

示例屏幕截图:

Screenshot

答案 1 :(得分:1)

@Xaviers的回答可以达到99%的效果。但是,用户可以意外地选中一个复选框,然后复选框的ToString()显示为所选文本。这实际上可能发生很多。我还没有弄清楚为什么会发生这种情况,但我已经找到了防止这种情况的方法。

创建一个绑定到组合框的DropDownOpen属性的bool属性,当DropDownOpen更改为false时,意味着DropDown刚刚关闭,您可能遇到上述问题。 因此,您只需为viewmodel引发propertychanged事件,并将绑定到组合框的Text属性的属性传递给它。

答案 2 :(得分:0)

使用@ Erik83和@Xavier解决方案的组合我仍然遇到这样的问题:在CheckBox文本中选择一个ComboBoxItem会关闭ComboBox-DropDown并显示ComboBoxItem的ToString()值,因为CheckBox是没有拉伸到DropDown-Width。我通过添加

解决了这个问题
  

Horizo​​ntalContentAlignment = “拉伸”

到CheckBox并添加ItemContainerStyle:

<ComboBox x:Name="combobox"
    Background="White"
    Padding="2"
    Text="{Binding ElementName=DockPanelTemplateComboCheck, Path=ComboTextFilter}"
    IsEditable="True"
    IsReadOnly="True"
    HorizontalAlignment="Stretch"
    ItemsSource="{Binding ...}"
    IsDropDownOpen="{Binding Path=DropOpen, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Eintrag}" HorizontalContentAlignment="Stretch" Checked="CheckBox_Checked_Unchecked" Unchecked="CheckBox_Checked_Unchecked"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
    <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

代码隐藏:

    private string combotextfilter = "<No Selection>";

    public string ComboTextFilter
    {
        get { return combotextfilter; }
        set
        {
            if (value != null && value.IndexOf("ComboModel") != -1) return;
            combotextfilter = value;
            NotifyPropertyChanged(nameof(ComboTextFilter));
        }
    }

    private void CheckBox_Checked_Unchecked(object sender, RoutedEventArgs e)
    {
        switch (((ObservableCollection<ComboModel>)combobox.ItemsSource).Count(x => x.IsChecked))
        {
            case 0:
                ComboTextFilter = "<No Selection>";
                break;
            case 1:
                ComboTextFilter = ((ObservableCollection<ComboModel>)combobox.ItemsSource).Where(x => x.IsChecked).First().Eintrag;
                break;
            default:
                ComboTextFilter = ((ObservableCollection<ComboModel>)combobox.ItemsSource).Where(x => x.IsChecked).Select(x => x.Eintrag).Aggregate((i, j) => i + " | " + j);
                //ComboTextFilter = "<Multiple Selected>";
                break;
        }

        NotifyPropertyChanged(nameof(C_Foreground));
    }

    public bool DropOpen
    {
        get { return dropopen; }
        set { dropopen = value; NotifyPropertyChanged(nameof(ComboTextFilter)); }
    }
    private bool dropopen = false;