选择用于显示的对象后,ComboBox值将消失

时间:2010-05-14 16:45:31

标签: c# wpf xaml combobox

我有一个组合框,我希望显示对象并返回枚举值。首次打开时,组合框会显示所谓的项目,但在选择一个值后,它似乎从列表中消失。但是如果组合框处于活动状态,我可以使用键盘在其他值之间上下导航,因此它们在列表中但只是不可见。

我已经创建了一个小测试应用程序来显示我的问题。启动时,应用程序会显示带有所有选项的组合框(两个首先是Object的类型,第三个是String):

All choices shown on startup http://i42.tinypic.com/ak7rll.png

选择蓝线后再次打开组合框时,此行缺失:

Blue line selected and is missing in popup http://i41.tinypic.com/24awgth.png

当选择带有文本“绿色”的行时,该行仍显示:

Green line selected and still shown in popup http://i41.tinypic.com/2en3g2r.png

如果我选择了红线,那么列表中唯一仍然是测试“绿色”。

我正在使用.NET Framework 3.5。

有关元素消失的任何提示或提示?


以下是在Visual Studio中启动空白项目后所需的所有代码。

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Test
{
   public partial class MainWindow
   {
      public MainWindow()
      {
         InitializeComponent();
      }

      private ColorComboBoxValue _activeColor;
      public ColorComboBoxValue ActiveColor
      {
         get { return _activeColor; }
         set
         {
            _activeColor = value;
            Debug.WriteLine("ActiveColor: " + _activeColor.Color);
         }
      }
   }

   public class ColorList : List<ColorComboBoxValue> { }

   public class ColorComboBoxValue
   {
      public Color Color { get; set; }
      public Object Object { get; set; }
   }

   public enum Color
   {
      Red,
      Blue,
      Green
   }
}

MainWindow.xaml:

<Window x:Class="Test.MainWindow" x:Name="window"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:Test"
        Title="ComboBoxTest" Height="100" Width="200">

    <Window.Resources>
        <local:ColorList x:Key="ColorList">
            <local:ColorComboBoxValue Color="Red">
                <local:ColorComboBoxValue.Object>
                    <Path Data="M0,0 L0,30 60,30 60,0 Z" Fill="Red"/>
                </local:ColorComboBoxValue.Object>
            </local:ColorComboBoxValue>
            <local:ColorComboBoxValue Color="Blue">
                <local:ColorComboBoxValue.Object>
                    <Path Data="M0,0 L0,30 60,30 60,0 Z" Fill="Blue"/>
                </local:ColorComboBoxValue.Object>
            </local:ColorComboBoxValue>
            <local:ColorComboBoxValue Color="Green">
                <local:ColorComboBoxValue.Object>
                    <System:String>Green</System:String>
                </local:ColorComboBoxValue.Object>
            </local:ColorComboBoxValue>
        </local:ColorList>
    </Window.Resources>

    <ComboBox ItemsSource="{Binding Source={StaticResource ColorList}}"
              SelectedItem="{Binding ActiveColor, ElementName=window}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <ContentPresenter Content="{Binding Path=Object}"/>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
</Window>

1 个答案:

答案 0 :(得分:3)

非常简单。

Path是一个WPF对象,因此,每个WPF对象只能有一个父对象。一旦WPF对象具有父集,就不能在另一个父集中使用它。

这会发生什么,DataTemplate被加载,它会显示你的项目。您选择一个带有Path的项目,它将在Combobox的Selected Item ContentPresenter中设置(必须显示)。这会将Path与原始对象分离,从而导致项目“消失”。您的项目仍然存在,但由于路径已从原始列表中分离,因此它不再可见,因此您无法看到它们。在字符串的情况下它起作用,因为字符串不是WPF对象。

希望这可以解决一些问题。

所以,现在寻求解决方案:

如果您希望将绿色保留为文本,则可以执行以下操作:

制作Color enum类型的ColorList:

public class ColorList : List<Color> { }

扔掉一些东西:

public partial class Window1 : Window
{
       public Window1()
    {
        this.Resources["ColorList"] = new[] { Color.Red, Color.Blue, Color.Green };
        InitializeComponent();
    }

       private Color _activeColor;
    public Color ActiveColor
    {
        get { return _activeColor; }
        set
        {
            _activeColor = value;
        }
    }
}

public class ColorList : List<Color> { }


public enum Color
{
    Red,
    Blue,
    Green
}

展开DataTemplate,使用DataTemplate中的Trigger对象为Red和Blue设置特定的数据窗口:

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication6="clr-namespace:WpfApplication6"
Title="ComboBoxTest" Height="100" Width="200">


<ComboBox ItemsSource="{Binding Source={StaticResource ColorList}}"
          SelectedItem="{Binding ActiveColor, ElementName=ComboBoxTest}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding}" x:Name="content" />
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding}" Value="{x:Static WpfApplication6:Color.Red}">
                    <Setter TargetName="content" Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <Path Data="M0,0 L0,30 60,30 60,0 Z" Fill="Red"/>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding}" Value="{x:Static WpfApplication6:Color.Blue}">
                    <Setter TargetName="content" Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <Path Data="M0,0 L0,30 60,30 60,0 Z" Fill="Blue"/>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
</Window>

干净的方法:

如果您希望让所有项目成为颜色对象,则需要一个转换器对象将Color枚举值转换为您想要显示的颜色:

<ComboBox ItemsSource="{Binding Source={StaticResource ColorList}}"
          SelectedItem="{Binding ActiveColor, ElementName=ComboBoxTest}">
    <ComboBox.ItemTemplate>
          <DataTemplate>
              <Path Data="M0,0 L0,30 60,30 60,0 Z" Fill="{Binding Converter={StaticResource ColorConverter}}"/>
          </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

您需要添加到资源的好转换器:

public class ColorConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        switch ((Color)value)
        {
            case Color.Red:
                return Colors.Red;
            case Color.Blue:
                return Colors.Blue;
            case Color.Green:
                return Colors.Green;
            default:
                throw new ArgumentOutOfRangeException("value");
        }
    }

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

    #endregion
}

更干净;)希望这有帮助..如果您有任何问题,我会在评论中回答!