ComboBox - выбрать объект из двух свойств - PullRequest
1 голос
/ 23 января 2012

Я хочу, чтобы мой пользователь мог выбирать клиента (пользовательский объект) из ComboBox в WPF. ComboBox покажет всем клиентам их FirstName (строка) и LastName (строка).

Таким образом, в основном моя ViewModel предоставляет одного Клиента, который будет выбран пользователем, и список всех Клиентов, которые будут использоваться для заполнения ComboBox. Объявление ComboBox выглядит так:

<ComboBox Grid.Row="3" Grid.Column="1" Text="{Binding Client}" ItemsSource="{Binding Clients}" IsEditable="True">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding StringFormat="{}{0} {1}">
                        <Binding Path="FirstName"/>
                        <Binding Path="LastName"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Конечно, это не работает, потому что свойство Text отображает необработанного клиента (с указанием имени типа), и если пользователь вводит имя, оно не может быть преобразовано в Client. Похоже, что это очень простая вещь, но пока я ищу в Интернете, я нахожу десятки разных решений: создать тип обертки с правильно отформатированным именем, использовать преобразователь значений, использовать шаблоны данных ... Я не знаком со всеми эти методы WPF, поэтому, пожалуйста, помогите мне найти лучшее (и, надеюсь, простое!) решение.

Спасибо!

Ответы [ 4 ]

3 голосов
/ 23 января 2012

Есть даже более простой способ сделать это.Как вы сказали, XAML привязывается к typename объекта, и это происходит из метода ToString ().Это позволяет вам переопределить метод и вернуть желаемое форматирование без сложных многократных привязок.

protected override ToString()
{
   return String.Format("{0} {1}", FirstName, LastName);
}

Возможно ли, что вы используете Text свойство неверно и вам нужен SelectedItem?

2 голосов
/ 23 января 2012

Не могли бы вы попробовать что-то подобное?

<!-- Example assumes DataContext of ComboBox is MasterViewModel below -->
<ComboBox Grid.Row="3" Grid.Column="1" ItemsSource="{Binding Clients}" IsEditable="True">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text={Binding FirstName} Margin="0,0,10,0"/>
                <TextBlock Text={Binding LastName}/>
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Затем привязать непосредственно к свойствам viewmodel

public class ClientViewModel: INotifyPropertyChanged
{
    public event EventHandler<PropertyChangedEventArgs> PropertyChanged; 

    private string firstName;
    private string lastName;

    public string FirstName
    {
        get { return this.firstName; }
        set 
        {
            this.firstName = value; // Dont forget to raise PropertyChanged!
        }
    }

    public string LastName
    {
        get { return this.firstName; }
        set 
        {
            this.lastName = value;
        }
    }
}

Предоставление IEnumerable<ClientViewModel> в вашей MasterViewModel следующим образом

public class MasterViewModel : INotifyPropertyChanged
{
    private IEnumerable<ClientViewModel> _clients = new ClientViewModel[] 
    {
        new ClientViewModel() { FirstName = "Dave", LastName = "Cameron" }, 
        new ClientViewModel() { FirstName = "Ed", LastName = "Miliband" }, 
    }
    public IEnumerable<ClientViewModel> Clients
    {
        get { return _clients; } 
    } 
}

Мощь DataTemplates означает, что вы можете представлять свои данные так, как вам нравится. Использование StackPanel или Grid в DataTemplate и нескольких текстовых полях - лучший способ перейти сюда.

С наилучшими пожеланиями

1 голос
/ 23 января 2012

Это должно работать из коробки, но вы, кажется, не привязываете выбранный элемент комбо.

<ComboBox Grid.Row="3" Grid.Column="1" IsEditable="True"
          ItemsSource="{Binding Clients}"
          SelectedItem="{Binding Client}" >

Мне не ясно, почему у вас есть комбо редактируемый. Вы говорите, что пользователь может ввести имя / фамилию, чтобы выбрать? В этом случае вам нужен конвертер.

1 голос
/ 23 января 2012

Я думаю, что самый простой способ - просто добавить пользовательское свойство к объекту Client.Таким образом, клиент оказывается таким.Обратите внимание, что объект Client ДОЛЖЕН реализовывать INotifyPropertyChanged в том или ином отношении, чтобы инфраструктура привязки могла реагировать на изменения.

public class Client : INotifyPropertyChanged
{
   //other fields/properies
   private string firstName;
   private string lastName;

   public string FirstName
   {
      get { return this.firstName; }
      set 
      {
         this.firstName = value;
         this.FirePropertyChanged("FirstName");
         this.FirePropertyChanged("DisplayName");
      }
   }

   public string LastName
   {
      get { return this.firstName; }
      set 
      {
         this.lastName = value;
         this.FirePropertyChanged("LastName");
         this.FirePropertyChanged("DisplayName");
      }
   }

   public string DisplayName
   {
      get 
      {
          return string.Format("{0} {1}", this.firstName, this.lastName);
      }
   }

   protected void FirePropertyChanged(string propertyName)
   {
      if (this.PropertyChanged != null)
         this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }
}

Тогда у вас есть очень простая декларация ComboBox, указывающаяв новом свойстве DisplayName:

РЕДАКТИРОВАТЬ:

Вместо использования свойства Text используйте свойство SelectedItem с двусторонней привязкой для соответствияэто до вашей ViewModel.

<ComboBox Grid.Row="3" Grid.Column="1" SelectedItem="{Binding Client, Mode=TwoWay" ItemsSource="{Binding Clients}" DisplayMemberPath="DisplayName" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...