我在以下场景中使用WPF ComboBox时遇到麻烦:
视图模型
ObservableCollection<T>
;此集合包含用户可以选择的项目列表。T
类型的属性。用户应该能够从ObservableCollection<T>
中的项目中选择现有项目,或者通过键入字符串表示来添加新项目。
我有一个转换器可以将T
类型的项目转换为string
,反之亦然。
视图
我的ComboBox绑定到集合和选定的项属性:
<ComboBox ItemsSource="{Binding Path=MyObservableCollection}"
SelectedItem="{Binding Path=MySelectedItem}"
IsReadOnly="False" IsEditable="True"/>
用于正确显示项目的数据模板:
<DataTemplate DataType="{x:Type T}">
<TextBlock Text="{Binding Converter={StaticResource ResourceKey=MyConverter}}"/>
</DataTemplate>
问题
使用转换正确显示ComboBox
下拉列表中的项目。显示在TextBox
的ComboBox
中的所选项目未正确显示;不使用我的转换器,而是使用ToString
方法。
是否可以为Text属性指定转换器?我尝试使用以下代码:
<ComboBox ItemsSource="{Binding Path=MyObservableCollection}"
SelectedItem="{Binding Path=MySelectedItem}"
Text="{Binding Path=MySelectedItem, Converter={StaticResource ResourceKey=MyConverter}}"
IsReadOnly="False" IsEditable="True"/>
这解决了显示问题,但现在我在转换器Type.FullName
方法中获得了T的ConvertBack
- 当然不能转换。
摘要
我希望用户能够从集合中选择一个项目,允许他通过输入字符串表示来添加新项目。集合中的项目应使用转换器在字符串和对象表示之间进行转换。转换应在下拉列表和ComboBox的文本框中完成。
编辑
这是我的转换器中的代码 - 没有什么魔法可以直接转换:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return MyConverter.Convert(value as T);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return MyConverter.Convert(value as string);
}
public static string Convert(T key)
{
// Conversion from T to string.
}
public static T Convert(string key)
{
// Conversion from string to T.
}
}
好的,现在我找到了能满足我要求的东西:
<TextBox Text="{Binding Path=MySelectedItem, Converter={StaticResource ResourceKey=MyConverter}}"/>
<ListBox ItemsSource="{Binding Path=MyObservableCollection}"
SelectedItem="{Binding Path=MySelectedItem, Converter={StaticResource ResourceKey=MyConverter}}"/>
这正是我想要的;我可以选择预定义的值,用户可以自己添加值。是否可以使用ComboBox执行此操作?
我已经尝试过了,但它并不合乎逻辑,因为转换器也应该得到集合的实例(在键入时添加内容)并且我认为尝试这样做会看起来很脏。你试过逆转逻辑吗?这是一个有效的例子,但我不知道它是否完全符合你的需要。
<ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox1"
VerticalAlignment="Top" Width="163"
ItemsSource="{Binding}"
DisplayMemberPath="Name" IsEditable="True"
TextBoxBase.TextChanged="comboBox1_TextChanged"/>
代码背后:
ObservableCollection<Type> types = new ObservableCollection<Type>( );
public MainWindow( )
{
InitializeComponent( );
types.Add( typeof( string ) );
types.Add( typeof( bool ) );
types.Add( typeof( int ) );
types.Add( typeof( decimal ) );
types.Add( typeof( double ) );
comboBox1.DataContext = types;
}
private void comboBox1_TextChanged( object sender , TextChangedEventArgs e )
{
if ( !( comboBox1.SelectedValue == null && !String.IsNullOrEmpty( comboBox1.Text ) ) ) { return; }
var type = Type.GetType( String.Format( "System.{0}" , comboBox1.Text ) , false , true );
if ( type != null && !types.Contains(type))
{
types.Add( type );
}
}
现在尝试在ComboBox中输入类似'datetime'的内容。
我现在使用不同的方法解决问题:
我的视图模型提供了一个可观察的集合和一个字符串属性。该集合绑定到ComboBox的ItemsSource属性,所选项绑定到字符串属性。
<ComboBox
ItemsSource="{Binding Path=MyCollection}"
Text="{Binding Path=MyProperty, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
IsReadOnly="False" IsEditable="True"/>
UpdateSourceTrigger=LostFocus
部分用于防止不必要的更新。
如果有人遇到相同的问题,并且不想应对要绑定的字符串属性。
您可以使用以下内容
<ComboBox
ItemsSource="{Binding Path=MyObservableCollection}"
Text="{Binding MySelectedItem, Converter={StaticResource DisplayConverter}}"
SelectedValue="{Binding MySelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource DisplayConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
请注意,绑定是在SelectedValue上完成的,而不是SelectedItem。然后将显示转换器添加到Text&Itemtemplate属性中。
我甚至将这个片段与来自在xaml中定义的ObjectDataProvider的Enum集合一起使用。我的枚举具有DisplayString属性,并且combobox表现得很好,可以显示枚举的字符串值表示。
HTH