如何将来自不同列表框的selectedItem绑定到一个文本框?

时间:2015-05-17 05:10:14

标签: c# wpf xaml binding listbox

我是WPF的新手,我遇到了绑定问题。

我有3个列表框,我想绑定到一个文本框。在listbox1中,我有一个名字" John Doe",在listbox2" Brian Warner"在listbox3" Anne Brown"。

当我点击" John Doe"它显示了" John Doe"在文本框中,我可以更改他的名字,因为我在我的xaml中有这个

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

现在我想将同一个文本框的值更改为&#34; Brian Warner&#34;当我在Listbox2中选择它时,将相同的文本框更改为&#34; Anne Brown&#34;当我在Listbox3中选择她的名字时。 我还希望能够编辑他们的名字并在列表框中更新。

我想我需要找到一种方法,每次我在列表框中选择和项目时,将绑定的ElementName从Listbox1更改为Listbox2,再更改为listbox3。

我该怎么做?我非常环保,我找不到任何如何做到这一点的例子。我希望我能提供更多代码,但我不知道从哪里开始。谢谢你的帮助。

更新

我设法通过使用

从专用文本框中的3个列表框中获取所需的值
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;
       }

但是当我尝试更改文本框中的值时,它不会在列表框中更新。我怎么能这样做?

3 个答案:

答案 0 :(得分:0)

好吧,你可以在代码等等处理这种绑定等等。但是,我会实现更简单的解决方案:只需在相同的布局和样式(或不是)中创建3个文本框,每个文本框都绑定到特定的列表框,当你举起列表框的onItemSelected事件时,只显示相关的文本框并折叠另一个。 Vuala!没有任何可能导致麻烦的绑定处理。

答案 1 :(得分:0)

一个简单的解决方案可能是

1-定义一个保存listbox ref的变量 2-对所有三个使用OnItemSelectionChange事件 3-更新标志以指示调用哪个控制事件 4-更改每个事件的文本框值 5-在文本框中更改值时,使用标志更改列表框中的值。

将文本框与三个列表框绑定是不合逻辑的。

答案 2 :(得分:0)

如果我正确理解了这个问题,那么您有一个编辑字段(TextBox),您希望用它来显示和编辑Name中所选数据对象的ListBox属性。 1}}。有多个此类ListBox个对象,用户应该能够编辑在最近使用的ListBox中选择的数据对象。

事实证明,这不是一件非常重要的事情。我同意Ben Cohen的回复,其中一种方法是在焦点发生变化时显示和隐藏不同的 TextBox个实例。一个相关但不同的方法是只有一个TextBox,并在焦点变化时更新其Binding属性。

但它比这更复杂,因为当用户选择ListBox中的项目时,ListBox本身并不是获得焦点的对象。它是ListBoxItem中的ListBox。在XAML中访问所选的ListBoxItem似乎并不方便。但即使你可以,还有另一个问题......

此外,您无法简单地将每个TextBox的可见性绑定到焦点状态(或合适的代理),因为只要用户实际点击TextBoxListBox /其代理失去了重点。

无论如何,有点摆弄这个问题(坦率地说,可能比我应该有的多,但是嘿......我也在这里学习新东西:)),我想出了一个代码示例,我认为正是你在这里要求的(我希望反过来你想要的:) :):

<强> 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的{​​{1}}属性,以使包含ListBox的属性设置为ListBoxItem,而另外两个true设置为false

通过这种方式,我使用Tag属性作为IsFocused ListBoxItem属性的代理,允许我的TextBox元素拥有VisibilityTag元素绑定到那个属性。请注意,我只在焦点收到时才设置TextBox。这样,即使在用户选择ListBox元素时焦点丢失,仍然可以设置可见性。

运行此程序时,每个TextBox仅使用一个项目进行初始化。选择项目时,它将显示在右侧的TextBox中。当三个ListBox元素及其项目之间的焦点发生变化时,会显示和隐藏不同的TextBox元素,但对于用户来说,它看起来只是单个TextBox正在更新以反映当前选择

如果您修改Name中的文字,则链接项的ListBox属性会像您一样更新。此更改当然会反映在Tag

中的显示中


我无法向您承诺,这是最佳方式。但它确实有效。我最大的抱怨是劫持Binding财产。但事实是,只要您不将该财产用于其他任何事情,就可以将其用于此目的。

我实际上希望有一些真正的WPF专家来告诉我,我是一个假人,并且有更好的方法来实现这一目标。但与此同时,我希望上述内容能够充分满足您的需求。 :)


我在上面提到过,替代方案是为单个TextBox元素更新TextBox。我还没有显示代码,但它不会有太大的不同。当然,您只有GotFocusListBox.Tag事件处理程序而不是弄乱ListBoxItem属性,而是检索{{1}的实际数据对象发送事件,并相应地为单个Binding对象配置新的TextBox对象。

这种方法可以避免使用Tag属性,甚至可能稍微提高效率(或者可能不是......它可以采用任何一种方式)。我个人发现操作绑定的代码比上面设置属性值的代码要复杂一些。但是,由于需要走可视树以找到父ListBox,因此该代码变得复杂。所以也许这是洗漱。

除了这些差异之外,代码仍然会以相同的方式构建。