当发生输入字段时,如何使 Expander Header 与 ListBox 项一起更改?
* 我只是试图用一张图片发布这个,但是这个网站不允许我发布图片,直到我的声誉超过 10 New] 按钮被单击一次,“John Henry Doe”输入到 Name 字段,“123-4567”输入到 Phone 字段,然后以红色粗体显示“1) As I type here”,箭头指向 Name 和 Phone 字段,然后以红色粗体显示“2)这会改变”,箭头指向列表框中的“John Henry Doe:123-4567”项,然后以红色粗体显示“3)但这不会改变”,箭头指向“新扩展器接头的“联系人”。*
如上图所示(如果我被允许发布图像),当用户在 Name 或 Phone 字段中键入时,ListBox Item 会发生变化。它发生了变化,因为我对 KeyUp 事件执行了 .Refresh() 。但是,Expander 的 Header 应该同时发生变化。据我所知,没有 .Refresh() 。我希望 Expander 的 Header 像 ListBox 的 Item 一样更新,也就是说,在用户键入时。
ListBox 的DataContext 是Contact 类的一个可观察集合。Contact 类有一个名为 ListString 的属性,其 get 方法返回 ListItem() 方法的结果。ListBox 的 ItemTemplate 只是绑定到 ListString 属性。Expander 的 Header 绑定到 ListBox 的 SelectedItem.ListString 并且当前仅在选择不同的 ListBox 项目时更新。我需要在打字时更新它。
下面是代码背后的 XAML 和 C# 代码。在 ListBox 中选择一个条目之前,ListBox 右侧的控件是不可见的。[New] 按钮将一个新项目插入到 ListBox 中并选择它,从而将控件置于右侧以显示并将焦点赋予 Name 字段。当您在名称字段和/或电话字段中键入时,列表框中的相应项目将更新,但扩展器的标题不会更新。在您选择 ListBox 中的另一个项目之前,它不会更新。我希望它在 ListBox 项目更新的同时更新。我怎么做?
<Window x:Class="Binding_List_Expander_04.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Binding List Expander 04"
Height="350"
Width="530">
<Window.Resources>
</Window.Resources>
<Grid>
<StackPanel Orientation="Horizontal" Margin="3">
<StackPanel Orientation="Vertical" Margin="3">
<ListBox Name="ContactList"
ItemsSource="{Binding}"
Width="166"
Height="270"
Margin="0,0,0,3">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ListString}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="NewItem"
Content="New"
Click="Event_NewContact_Click"
Height="23"
Width="75" />
</StackPanel>
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<Style TargetType="ScrollViewer">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ContactList, Path=SelectedIndex}" Value="-1">
<Setter Property="Opacity" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<ScrollViewer Height="302">
<StackPanel Orientation="Vertical">
<Expander Name="ContactExpander">
<Expander.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementName=ContactList, Path=SelectedItem.ListString}" />
</DataTemplate>
</Expander.HeaderTemplate>
<StackPanel Margin="21,0,0,0"
Orientation="Vertical">
<Grid Margin="3"
TextBoxBase.TextChanged="Event_ContactName_TextChanged">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="3" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="Name:" />
<TextBox Grid.Row="0"
Grid.Column="2"
Name="ContactName"
Text="{Binding ElementName=ContactList, Path=SelectedItem.Name, Mode=TwoWay}" />
<TextBlock Grid.Row="2"
Grid.Column="0"
Text="Phone:" />
<TextBox Grid.Row="2"
Grid.Column="2"
Name="ContactPhone"
Text="{Binding ElementName=ContactList, Path=SelectedItem.Phone, Mode=TwoWay}" />
</Grid>
</StackPanel>
</Expander>
<Expander Header=" This is a place holder, there will be many Expanders following this one."
Margin="0,10,0,0">
<StackPanel>
<TextBlock Text="Data and Information" FontSize="30" TextAlignment="Center" />
</StackPanel>
</Expander>
<Expander Header="This is another place holder."
Margin="0,10,0,0">
<StackPanel>
<TextBlock Text="Data and Information" FontSize="30" TextAlignment="Center" />
</StackPanel>
</Expander>
<Expander Header="This is another place holder."
Margin="0,10,0,0">
<StackPanel>
<TextBlock Text="Data and Information" FontSize="30" TextAlignment="Center" />
</StackPanel>
</Expander>
</StackPanel>
</ScrollViewer>
</StackPanel>
</StackPanel>
</Grid>
</Window>
using System.Windows;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using System.Threading;
using System.Windows.Controls;
namespace Binding_List_Expander_04
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ObservableCollection<Contact> Contacts = new ObservableCollection<Contact>();
public MainWindow()
{
InitializeComponent();
ContactList.DataContext = Contacts;
}
private void Event_NewContact_Click(object sender, RoutedEventArgs e)
{
Contacts.Insert(0, new Contact());
ContactList.SelectedIndex = 0;
if (ContactExpander.IsExpanded)
SetFocus(ContactName);
else
{
ContactExpander.IsExpanded = true;
SetFocus(ContactName);
}
}
public void SetFocus(UIElement control)
{
control.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)delegate { control.Focus(); });
}
private void Event_ContactName_TextChanged(object sender, TextChangedEventArgs e)
{
var tb = e.Source as TextBox;
Contact C = ContactList.SelectedItem as Contact;
if (tb == ContactName)
C.Name = tb.Text;
else if (tb == ContactPhone)
C.Phone = tb.Text;
ContactList.Items.Refresh();
}
}
public class Contact
{
public string Name { get; set; }
public string Phone { get; set; }
public string ListString { get { return ListItem(); } } // See comments in ListItem() below.
public Contact()
{
Name = string.Empty;
Phone = string.Empty;
}
private string ListItem()
{/*
* This is a simplified version, the actual version is complicated and cannot be templatized.
* Please, do not suggest templitazing this. I know this simple version can be templitazed,
* but the actual version cannot be templatized. I need to know how to make this work as it
* currently is.
*/
if ((Name + Phone).Trim().Length == 0)
return "<New Contact>";
else
{
string li = Name.Trim();
if (li.Length != 0 && Phone.Trim().Length != 0) li += ": ";
return li + Phone.Trim();
}
}
}
}
谢谢你的帮助。