Если я правильно понял вопрос правильно, у вас есть одно поле редактирования (а 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
. Так что, возможно, это мойка.
Помимо этих отличий, код по-прежнему будет структурирован таким же образом.