2015-05-17 2 views
-1

Я очень новичок в WPF, и у меня возникла проблема с привязкой.Как связать selectedItem из разных списков в одно текстовое поле?

У меня есть 3 списка, которые я хочу связать с одним текстовым полем. В listbox1 у меня есть имя «John Doe», в спискеbox2 «Брайан Уорнер» и в спискеbox3 «Энн Браун».

Когда я нажимаю на «John Doe» он показывает «John Doe» в текстовом поле, и я могу изменить его имя, потому что у меня есть это в моем XAML

<TextBox x:Name="Name" Text="{Binding ElementName=listbox1, Path=SelectedItem.Name}"/> 

Теперь я хочу, чтобы изменить значение из то же текстовое поле на «Брайан Уорнер», когда я выбираю элемент в спискеbox2 и меняю одно и то же текстовое поле на «Anne Brown», когда я выбираю ее имя в Listbox3. Я также хочу, чтобы иметь возможность редактировать их имя и обновлять его в списке.

Мне кажется, мне нужно найти способ изменить привязку ElementName из Listbox1 в Listbox2, в listbox3 каждый раз, когда я выбираю, и элемент в списке.

Как это сделать? Я очень зеленый, и я не могу найти примеров того, как это сделать. Хотелось бы, чтобы я мог предоставить еще какой-нибудь код, но я не знаю, с чего начать. Спасибо за вашу помощь.

ОБНОВЛЕНИЕ

мне удалось получить желаемые значения из 3 ListBoxes в выделенных текстовых с помощью

SelectionChanged="listBox_SelectionChanged" 

в XAML для каждого текстового поля.

private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
     { 
      tb_firstName.Text = ((sender as ListBox).SelectedItem as Person).FirstName; 
      tb_lastName.Text = ((sender as ListBox).SelectedItem as Person).LastName; 
      tb_occupation.Text = ((sender as ListBox).SelectedItem as Person).Occupation; 
      tb_characteristics.Text = ((sender as ListBox).SelectedItem as Person).Characteristics; 
      tb_email.Text = ((sender as ListBox).SelectedItem as Person).Email; 
      tb_phoneNr.Text = ((sender as ListBox).SelectedItem as Person).PhoneNr; 
      tb_moreInfo.Text = ((sender as ListBox).SelectedItem as Person).MoreInfo; 
      tb_group.Text = ((sender as ListBox).SelectedItem as Person).Group; 
     } 

но когда я пытаюсь изменить значение в текстовом поле, оно не обновляется в списке. Как я могу это сделать?

ответ

0

Ну, вы можете справиться с такой привязкой в ​​коде позади и т. Д. Но я бы реализовал упрощенное решение: просто создайте 3 текстовых поля в одном макете и стиле (или нет), каждый из которых привязан к конкретный список, а когда вы поднимаете событие onItemSelected в списке, просто покажите соответствующее текстовое поле и скройте другое. Vuala! без каких-либо привязок, которые могут вызвать проблемы.

0

Простое решение может быть

1- определить переменную, которая сохраняет в окне списка REF 2- использовать OnItemSelectionChange событие для всех трех 3- обновление флаг, чтобы указать, какой контроль событие называется 4- Изменение значение текстового поля из каждого события 5- когда значение изменено в текстовом поле, используйте флаг, чтобы изменить это значение в списке.

Нелогично связывать текстовое поле с тремя списками.

0

Если я правильно понял вопрос правильно, у вас есть одно поле редактирования (а TextBox), который вы хотели бы использовать для отображения и редактирования Name свойство объекта данных, выбранного в ListBox. Существует несколько таких объектов ListBox, и пользователь должен иметь возможность редактировать объект данных, который выбран в последнем обновленном ListBox.

Как оказалось, это не совсем тривиальная вещь.Я согласен с ответом Бен Коэна в том, что один подход заключается в том, чтобы показать и скрыть разныеTextBox экземпляры с изменением фокуса. Связанный, но другой подход состоит в том, чтобы иметь только один TextBox и обновить его свойство Binding об изменениях в фокусе.

Но это сложнее, потому что, когда пользователь выбирает элемент в ListBox, сам объект ListBox не является объектом, который получает фокус. Это ListBoxItem в ListBox, что делает. Кажется, что нет удобного способа доступа в XAML ListBoxItem, который выбран. Но даже если бы вы могли, есть еще одна проблема & hellip;

Кроме того, вы не можете просто связать видимость каждого TextBox к сфокусированного состояния (или подходящий прокси-сервер), потому что, как только пользователь нажмет на самом деле в TextBox, то ListBox/его доверенное лицо теряет фокус.

В любом случае, немного поправившись с проблемой (честно говоря, возможно, больше, чем я должен был бы, но эй, эйип, я тоже кое-что изучаю :)), я придумал пример кода, который, как мне кажется, то, что вы просили здесь (я надеюсь, что, в свою очередь, что вы хотите :)):

XAML:

<Window x:Class="TestSO30283586BindOnFocus.MainWindow" 
     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:TestSO30283586BindOnFocus" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
    <DataTemplate x:Key="dataTemplate1" DataType="{x:Type local:A}"> 
     <TextBlock Text="{Binding Name}"/> 
    </DataTemplate> 
    <local:BoolToVisibilityConverter x:Key="boolToVisibilityConverter1"/> 
    <Style TargetType="ListBox"> 
     <Setter Property="ItemTemplate" Value="{StaticResource dataTemplate1}"/> 
     <Setter Property="Tag"> 
     <Setter.Value> 
      <system:Boolean>False</system:Boolean> 
     </Setter.Value> 
     </Setter> 
    </Style> 
    <Style TargetType="ListBoxItem"> 
     <EventSetter Event="GotFocus" Handler="listBoxItem_Focus"/> 
    </Style> 
    <Style TargetType="TextBox"> 
     <Setter Property="Grid.Column" Value="1"/> 
     <Setter Property="FontSize" Value="16"/> 
    </Style> 
    </Window.Resources> 

    <Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition/> 
     <ColumnDefinition/> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <ListBox x:Name="listBox1" 
      Grid.Row="0"> 
     <ListBox.Items> 
     <local:A Name="John"/> 
     </ListBox.Items> 
    </ListBox> 

    <ListBox x:Name="listBox2" 
      Grid.Row="1"> 
     <ListBox.Items> 
     <local:A Name="Jacob"/> 
     </ListBox.Items> 
    </ListBox> 
    <ListBox x:Name="listBox3" 
      Grid.Row="2"> 
     <ListBox.Items> 
     <local:A Name="Jingleheimer"/> 
     </ListBox.Items> 
    </ListBox> 

    <TextBox Text="{Binding ElementName=listBox1, Path=SelectedItem.Name, UpdateSourceTrigger=PropertyChanged}" 
      Visibility="{Binding ElementName=listBox1, Path=Tag, Converter={StaticResource boolToVisibilityConverter1}}"/> 
    <TextBox Text="{Binding ElementName=listBox2, Path=SelectedItem.Name, UpdateSourceTrigger=PropertyChanged}" 
      Visibility="{Binding ElementName=listBox2, Path=Tag, Converter={StaticResource boolToVisibilityConverter1}}"/> 
    <TextBox Text="{Binding ElementName=listBox3, Path=SelectedItem.Name, UpdateSourceTrigger=PropertyChanged}" 
      Visibility="{Binding ElementName=listBox3, Path=Tag, Converter={StaticResource boolToVisibilityConverter1}}"/> 
    </Grid> 
</Window> 

C#:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void listBoxItem_Focus(object sender, RoutedEventArgs e) 
    { 
     ListBox[] listBoxes = { listBox1, listBox2, listBox3 }; 
     ListBoxItem item = (ListBoxItem)sender; 
     ListBox listBoxParent = GetParent<ListBox>(item); 

     foreach (ListBox listBox in listBoxes) 
     { 
      listBox.Tag = object.ReferenceEquals(listBoxParent, listBox); 
     } 
    } 

    private static T GetParent<T>(DependencyObject o) where T : DependencyObject 
    { 
     while (o != null && !(o is T)) 
     { 
      o = VisualTreeHelper.GetParent(o); 
     } 

     return (T)o; 
    } 
} 

class A : DependencyObject 
{ 
    public static readonly DependencyProperty NameProperty = DependencyProperty.Register(
     "Name", typeof(string), typeof(A)); 

    public string Name 
    { 
     get { return (string)GetValue(NameProperty); } 
     set { SetValue(NameProperty, value); } 
    } 
} 

class BoolToVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (!(value is bool)) 
     { 
      return Binding.DoNothing; 
     } 

     return (bool)value ? Visibility.Visible : Visibility.Hidden; 

    } 

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

Есть немного кода для решения проблем, с которыми я не мог обращаться в разметке. В частности, код-код включает обработчик событий, который запускается в любое время, когда ListBoxItem получает фокус. Когда это произойдет, обработчик события обновляет свойство Tag каждого ListBox, так что тот, в котором находится ListBoxItem, установлен в true, а два других - false.

Таким образом, я использую Tag свойство в качестве прокси-сервера для IsFocused собственности ListBoxItem, позволяя мои TextBox элементы, чтобы их Visibility свойства связаны с этим. Обратите внимание, что я устанавливаю только Tag, когда фокус принят. Таким образом, видимость остается установленной, даже когда фокус теряется, когда пользователь выбирает элемент TextBox.

При запуске этой программы каждый ListBox инициализируется только одним элементом. Когда вы выбираете элемент, он отображается в TextBox справа. Различные элементы TextBox показаны и спрятаны как изменения фокуса между тремя элементами и их элементами, но для пользователя он просто выглядит как один TextBox обновляется, чтобы отразить текущий выбор.

Если вы отредактируете текст в TextBox, свойство Name связанного элемента будет обновлено, как и вы. Это изменение, конечно, отражается на дисплее в ListBox.


Не могу пообещать вам, что это best Способ для этого. Но это действительно работает. Моя самая большая жалоба на это - захват имущества Tag.Но факт в том, что, пока вы не используете это свойство ни для чего другого, вероятно, хорошо использовать его для этой цели.

Я действительно надеюсь, что какой-нибудь настоящий эксперт WPF придет и скажет мне, что я манекен, и есть намного лучший способ добиться этого. Но в то же время я надеюсь, что вышеупомянутое подойдет вам адекватно. :)


я уже упоминалось выше, что альтернативой было бы, чтобы обновить Binding для одного TextBox элемента. Я не показал код для этого, но это было бы не слишком много. Конечно, у вас будет только один TextBox, и обработчик события GotFocus вместо того, чтобы возиться с свойством ListBox.Tag, вместо этого получит фактический объект данных для отправки ListBoxItem события и сконфигурирует новый объект Binding соответственно для одного объекта TextBox ,

Этот подход позволит избежать использования свойства Tag и может даже быть немного более эффективным (или может и не быть & hellip; он может идти в любом случае). Я лично нахожу код, чтобы манипулировать привязками немного сложнее, чем предыдущий код, который просто устанавливает значение свойства. Но этот код осложняется необходимостью подойти к визуальному дереву, чтобы найти родителя ListBox. Так что, возможно, это мойка.

Помимо этих отличий, код по-прежнему будет структурирован таким же образом.

Смежные вопросы