带有复选框的WPF组合框显示有关选中项的信息?

vjhs03f7  于 2023-08-07  发布在  其他
关注(0)|答案(4)|浏览(125)

我试图使一个组合框,有复选框作为项目,并根据什么是检查显示不同的东西时,组合框是“关闭”。
我试图实现的外观可以在图像中看到。
x1c 0d1x的数据
理想情况下,我不希望用户能够选择顶部的文本(在图像中)。
有没有简单的解决办法?我见过一些解决方案,其中可以显示更多的信息时,所有的项目显示使用DataTriggers隐藏不同的嵌套控件,但这不是真正的我在寻找什么。
有什么想法吗?
/Erik

cyvaqqii

cyvaqqii1#

下面是一种使用ComboBox实现大部分功能的方法,除了文本仍然可以被选择(使用自定义文本仅在IsEditable为true时有效)。由于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>

字符串

视图模型

// 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控件模板(默认示例here)。或者,您可以使用其他东西来代替ComboBox,并使其看起来像ComboBox
示例屏幕截图:


的数据

r1zhe5dt

r1zhe5dt2#

使用@Erik83和@Xavier解决方案的组合,我仍然遇到了一个问题,即在CheckBox文本的正确位置选择ComboBoxItem会关闭ComboBox-DropDown并显示ComboBoxItem的ToString()值,因为CheckBox没有拉伸到DropDown-Width。我通过加上
HorizontalContentAlignment=“拉伸”
并添加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>

字符串
CodeBehind:

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;

monwx1rj

monwx1rj3#

@Xaviers的答案99%有效。然而,用户能够意外地选择复选框,然后复选框的ToString()显示为所选文本。这实际上可能发生很多。我还没有弄清楚为什么会发生这种情况,但我已经找到了一种方法来防止这种情况。
创建一个绑定到组合框的DropDownOpen属性的bool属性,当DropDownOpen更改为false时,这意味着DropDown刚刚关闭,您可能会面临上述问题。因此,这里您只需为视图模型引发propertychanged事件,并传递绑定到组合框的Text属性的属性。

neskvpey

neskvpey4#

添加到所有其他答案中,如果你想摆脱勾选复选框时意外选择值的情况,你可以像下面这样覆盖ComboBoxItem的模板。这将删除原始的ComboBoxItem容器,只留下CheckBox容器,从而消除了该风险。

<ComboBox IsEditable="True" 
          IsReadOnly="True" 
          ItemsSource="{Binding ItemsSource}" 
          Text="{Binding SelectedValues, Mode=OneWay}">
    <ComboBox.ItemContainerStyle>
         <Style TargetType="ComboBoxItem">
              <Setter Property="Template">
                   <Setter.Value>
                         <ControlTemplate>
                              <CheckBox Content="{Binding Item.Value}" 
                                        IsChecked="{Binding 
                                        Item.IsChecked}">
                              </CheckBox>
                         </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

字符串

相关问题