在使用ItemContainerGenerator进行自定义时,WPF ComboBox在第二次打开之前不会更新项目

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在使用ItemContainerGenerator进行自定义时,WPF ComboBox在第二次打开之前不会更新项目相关的知识,希望对你有一定的参考价值。

我正在尝试使用动态组合框创建一个对话框,该组合框会根据其他组合框具有的所选项目来更改项目文本的颜色。我已经通过让组合框的下拉开启事件启动一个循环来测试每个组合框的值与另一个组合框的选定值,根据它是更大还是更小来改变颜色。

它主要使用ComboBox.ItemContainerGenerator直接自定义组合框,但直到组合框第二次打开时才更新颜色。

我用更简单的组合框重新创建了这个问题:

XAML:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DisposableXAML"
        xmlns:Properties="clr-namespace:DisposableXAML.Properties" 
        x:Class="DisposableXAML.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow" Height="306" Width="396">
    <Canvas>
        <ComboBox x:Name="combobox1" Canvas.Left="129" Canvas.Top="44" Width="120" SelectedIndex="0"/>

        <ComboBox x:Name="combobox2" Canvas.Left="129" Canvas.Top="117" Width="120" DropDownOpened="combobox2_DropDownOpened"/>
    </Canvas>
</Window>

C#:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace DisposableXAML
{

    public partial class MainWindow : Window
    {
        List<int> intList;

        public MainWindow()
        {
            InitializeComponent(); 

            DataContext = this;
            intList = new List<int>() { 1, 2, 3, 4 };

            combobox1.ItemsSource = intList;
            combobox2.ItemsSource = intList;
        }

        private void combobox2_DropDownOpened(object sender, EventArgs e)
        {
            int SelectedNum = (int) combobox1.SelectedItem;

            for (int i = 0; i < 4; i++)
            {
                ComboBoxItem item = (ComboBoxItem)combobox2.ItemContainerGenerator.ContainerFromIndex(i);;

                if (item != null)
                {
                    if (i < SelectedNum)
                    {
                        item.Background = Brushes.Green;
                    }
                    else
                    {
                        item.Background = Brushes.Blue;
                    }
                }
            }
        }
    }
}

Combobox首次开放:

Combobox第二次开放:

有没有办法让组合框在第一次打开时更新?还是有一种更清洁的方式可以实现这种效果?

答案

这是一种方法,主要使用XAML和单个MultiValueConverter。此示例根据第一个ComboBox中所选项目是更大,相等还是更小来设置第二个ComboBox中项目的背景颜色。

MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:ComparisonConverter x:Key="ComparisonConverter" />
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
            <RowDefinition />
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <ComboBox Name="Box1" ItemsSource="{Binding Items}" Grid.Column="1" Grid.Row="1" />
        <ComboBox Name="Box2" ItemsSource="{Binding Items}" Grid.Column="1" Grid.Row="3">
            <ComboBox.ItemContainerStyle>
                <Style TargetType="ComboBoxItem">
                    <Style.Triggers>
                        <DataTrigger Value="GT">
                            <DataTrigger.Binding>
                                <MultiBinding Converter="{local:ComparisonConverter}">
                                    <Binding ElementName="Box1" Path="SelectedItem" />
                                    <Binding />
                                </MultiBinding>
                            </DataTrigger.Binding>
                            <Setter Property="Background" Value="Red" />
                        </DataTrigger>
                        <DataTrigger Value="LT">
                            <DataTrigger.Binding>
                                <MultiBinding Converter="{local:ComparisonConverter}">
                                    <Binding ElementName="Box1" Path="SelectedItem" />
                                    <Binding />
                                </MultiBinding>
                            </DataTrigger.Binding>
                            <Setter Property="Background" Value="Blue" />
                        </DataTrigger>
                    </Style.Triggers>
                    <Setter Property="Background" Value="Green" />
                </Style>
            </ComboBox.ItemContainerStyle>
        </ComboBox>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System.Collections.Generic;
using System.Windows;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private List<int> items;

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            this.items = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
        }

        public List<int> Items
        {
            get
            {
                return this.items;
            }
        }
    }
}

ComparisonConverter.cs:

using System;
using System.Linq;
using System.Windows.Data;
using System.Windows.Markup;

namespace WpfApplication1
{
    public class ComparisonConverter : MarkupExtension, IMultiValueConverter
    {
        public ComparisonConverter()
        {
        }

        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string result = null;
            if (values.Count() >= 2)
            {
                int value1 = System.Convert.ToInt32(values[0]);
                int value2 = System.Convert.ToInt32(values[1]);

                if (value1 > value2)
                {
                    result = "GT";
                }
                else if (value1 < value2)
                {
                    result = "LT";
                }
                else
                {
                    result = "EQ";
                }
            }

            return result;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }
}

以上是关于在使用ItemContainerGenerator进行自定义时,WPF ComboBox在第二次打开之前不会更新项目的主要内容,如果未能解决你的问题,请参考以下文章

TreeView虚拟化跳转

获取ListBox中的ListBoxItem

如何在 wpf 中的 treeviewitem 中访问 treeviewitem?

无法在正在进行内容生成时调用 StartAt

WPF datagrid 行变色

更改 DataGrid 的颜色