WPF从ListView获取控制变量

本文关键字:控制变量 获取 ListView WPF | 更新日期: 2023-09-27 18:21:42

我正在使用WPF聊天,我为房间列表设计了ListView

主窗口.xaml

<ListView x:Name="listView_RoomList" Grid.Row="1" Grid.ColumnSpan="2"   
          ScrollViewer.HorizontalScrollBarVisibility="Visible" SelectionMode="Single"
          Visibility="{Binding ElementName=comboBox_CntList, Path=Items.IsEmpty,
                                      Converter={StaticResource VisibilityConverter}}">
    <ListView.View>
        <GridView ColumnHeaderTemplate="{Binding Path=Rooms}">
            <GridView.Columns>
                <GridViewColumn x:Name="gridViewColumn_RoomName" Width="100">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Label Content="{Binding Path=Name}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn x:Name="gridViewColumn_Master" Width="100">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Label Content="{Binding Path=Master}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn x:Name="gridViewColumn_MaxConnectorNum">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Label Content="{Binding Path=MaxConnectorNum, Converter={StaticResource MaxConnectorNumConverter}}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn x:Name="gridViewColumn_IsNeedPassword">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <PasswordBox x:Name="passwordBox_PW" MinWidth="100" IsEnabled="{Binding Path=IsNeedPassword}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn x:Name="gridViewColumn_EntryButton">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button Background="Aqua" Click="button_Entry_Click">
                                <StackPanel Orientation="Horizontal">
                                    <Image Height="Auto" Width="Auto" Source="Resources/login.png"/>
                                    <TextBlock Text="{Binding Converter={StaticResource EntryButtonConverter}}" VerticalAlignment="Center"/>
                                </StackPanel>
                                <Button.Tag>
                                    <!-- I can get a Room ID!! -->
                                    <Binding Path="ID"/>
                                </Button.Tag>
                            </Button>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn x:Name="gridViewColumn_DeleteButton">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button Background="Orange" Click="button_Delete_Click" IsEnabled="{Binding Path=Master, Converter={StaticResource DeleteButtonVisibilityConverter}}">
                                <StackPanel Orientation="Horizontal">
                                    <Image Height="Auto" Width="Auto" Source="Resources/login.png"/>
                                    <TextBlock Text="{Binding Converter={StaticResource DeleteButtonConverter}}" VerticalAlignment="Center"/>
                                </StackPanel>
                            </Button>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

一个GridView Row具有Room类。

Room.cs

public class Room
{
        public uint ID { get; private set; }
        public string Name { get; private set; }
        public string Master { get; internal set; }
        public short MaxConnectorNum { get; private set; }
        public bool IsNeedPassword { get; private set; }
}

每个房间都有一个ID

因此,当调用button_Entry_Click函数时,我可以获得房间ID。

主窗口.xaml.cs

private void button_Entry_Click(object sender, RoutedEventArgs e)
        {
            Button b = (Button)sender;
            MessageBox.Show(b.Tag);
        }

像这样的东西。

我只能得到Button但是,我想得到输入密码等PasswordBox

因为我想找到从房间ID获取所有行控制的方法。

我该如何编码?

提前谢谢。

WPF从ListView获取控制变量

您需要从ListView获取容器,并遍历它的VisualTree来搜索PasswordBox控制

首先,这里有一些你可以使用的扩展,我一直都很方便。

public static class VisualTreeHelperExtensions
{
    public static T FindVisualParent<T>(DependencyObject depObj) where T : DependencyObject
    {
        var parent = VisualTreeHelper.GetParent(depObj);
        if (parent == null || parent is T)
            return (T)parent;
        return FindVisualParent<T>(parent);
    }
    public static T FindVisualChild<T>(DependencyObject depObj) where T : Visual
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    return (T)child;
                }
                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    return childOfChild;
                }
            }
        }
        return null;
    }
    public static T FindVisualChild<T>(DependencyObject depObj, string name) where T : FrameworkElement
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T && (child as T).Name.Equals(name))
                {
                    return (T)child;
                }
                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    if (childOfChild.Name.Equals(name))
                        return childOfChild;
                }
            }
        }
        return null;
    }
    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj == null)
            yield break;
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }
            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }               
}

下面是一个如何获取ListView:中第一个房间的PasswordBox的示例

CS:

    public List<Room> Rooms
    {
        get
        {
            return new List<Room> 
            { 
                new Room{ Name = "A"} , 
                new Room{ Name = "B"}
            };
        }
    }
    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        var rooms = listView_RoomList.Items.Cast<Room>().ToList();
        var generator = listView_RoomList.ItemContainerGenerator;
        ListViewItem container = (ListViewItem)generator.ContainerFromItem(rooms[0]);
        PasswordBox pwd = (PasswordBox)VisualTreeHelperExtensions.FindVisualChild<PasswordBox>(container);
        string password = pwd.Password;
    }

XAML:

  <Grid>
      <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition />
      </Grid.RowDefinitions>
       <Button Content="Submit" Click="Button_Click_1"  />
       <ListView x:Name="listView_RoomList" Grid.Row="1" ItemsSource="{Binding Rooms}"
              ScrollViewer.HorizontalScrollBarVisibility="Visible" SelectionMode="Single">
             <ListView.View>
                   <GridView>
                      <GridView.Columns>
                         <GridViewColumn>
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                   <TextBlock Text="{Binding Name}"/>
                                 </DataTemplate>
                             </GridViewColumn.CellTemplate>
                          </GridViewColumn>
                          <GridViewColumn>
                               <GridViewColumn.CellTemplate>
                                   <DataTemplate>
                                        <PasswordBox  />
                                   </DataTemplate>
                                </GridViewColumn.CellTemplate>
                           </GridViewColumn>                       
                    </GridView.Columns>
               </GridView>
           </ListView.View>
       </ListView>                
  </Grid>

或者你也可以这样做:

XAML:

     <GridViewColumn>
          <GridViewColumn.CellTemplate>
              <DataTemplate>                                  
                   <PasswordBox PasswordChanged="passwordBox_PW_PasswordChanged_1"  />
               </DataTemplate>
          </GridViewColumn.CellTemplate>
     </GridViewColumn>

CS:

    private void passwordBox_PW_PasswordChanged_1(object sender, RoutedEventArgs e)
    {
        PasswordBox pwdBox = (PasswordBox)sender;
        Room r = pwdBox.DataContext as Room;
        r.Password = pwdBox.Password;
    }