Привязка ComboBox Text свойство с помощью конвертера - PullRequest
2 голосов
/ 22 марта 2012

У меня проблемы с использованием WPF ComboBox в следующем сценарии:

ViewModel

  • Предоставляет 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.

Edit

Вот код в моем конвертере - никакой магии нетпрямое преобразование:

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?

Ответы [ 3 ]

0 голосов
/ 02 апреля 2012

Теперь я использую другой подход к проблеме:

Моя модель представления предоставляет наблюдаемую коллекцию и строковое свойство.Коллекция привязана к свойству ItemsSource ComboBox, выбранный элемент - к строковому свойству.

        <ComboBox
            ItemsSource="{Binding Path=MyCollection}" 
            Text="{Binding Path=MyProperty, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
            IsReadOnly="False" IsEditable="True"/>

UpdateSourceTrigger=LostFocus часть используется для предотвращения ненужных обновлений.

0 голосов
/ 05 октября 2016

В случае, если кто-то сталкивается с той же проблемой и не хочет иметь свойство привязки строки к.

Вы можете использовать следующее

<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.

  • В свойстве Text оно будет использоваться для преобразования отображаемого значения выбранного элемента.
  • В ItemTemplate для преобразования отображаемых значений в поле списка

Я даже использую этот фрагмент с коллекцией Enum из ObjectDataProvider, определенной в xaml.Мои перечисления имеют атрибут DisplayString, а выпадающий список отлично работает для отображения представления строковых значений перечислений.

HTH

0 голосов
/ 22 марта 2012

Я пробовал это, но это не совсем логично, потому что конвертер должен также получить экземпляр коллекции (чтобы добавить вещи во время набора текста), и я думаю, что попытка сделать это будет выглядеть грязной.Вы пытались изменить логику?Вот пример, который работает, однако я не знаю, точно ли он вам нужен.

<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 );
  }
}

Теперь попробуйте ввести что-то вроде 'datetime' вComboBox.

...