如何将标头添加到DualList控件wpf

时间:2010-04-19 19:41:44

标签: wpf

我正在尝试在wpf中编写双列表用户控件。

我是wpf的新手,我觉得很难。 这是我在几个小时内放在一起的东西。它不是那么好,而是一个开始。

如果具有wpf经验的​​人可以改进它,我将非常感激。 目的是尽可能简化使用

我有点卡住了。 我希望DualList Control的用户能够设置标头如何做到这一点。 我是否需要在我的控件中公开一些依赖项属性?

当加载用户必须传递一个ObservableCollection时,还有更好的方法吗?

你能看看并可能对某些代码提出任何建议吗?

非常感谢!!!!!

XAML

   <Grid ShowGridLines="False">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="25px"></ColumnDefinition>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Vertical" Grid.Column="0" Grid.Row="0">
        <Label Name="lblLeftTitle" Content="Available"></Label>
        <ListView Name="lvwLeft">
        </ListView>
    </StackPanel>
    <WrapPanel Grid.Column="1" Grid.Row="0">
        <Button Name="btnMoveRight" Content=">" Width="25" Margin="0,35,0,0" Click="btnMoveRight_Click" />
        <Button Name="btnMoveAllRight" Content=">>" Width="25" Margin="0,05,0,0" Click="btnMoveAllRight_Click" />
        <Button Name="btnMoveLeft" Content="&lt;" Width="25" Margin="0,25,0,0" Click="btnMoveLeft_Click" />
        <Button Name="btnMoveAllLeft" Content="&lt;&lt;" Width="25" Margin="0,05,0,0" Click="btnMoveAllLeft_Click" />
    </WrapPanel>
    <StackPanel Orientation="Vertical" Grid.Column="2" Grid.Row="0">
        <Label Name="lblRightTitle" Content="Selected"></Label>
        <ListView Name="lvwRight">
        </ListView>
    </StackPanel>
</Grid>

客户端

       public partial class DualListTest
    {
        public ObservableCollection<ListViewItem> LeftList { get; set; }
        public ObservableCollection<ListViewItem> RightList { get; set; }

        public DualListTest()
        {
            InitializeComponent();
            LoadCustomers();
            LoadDualList();
        }

        private void LoadDualList()
        {
            dualList1.Load(LeftList, RightList);
        }

        private void LoadCustomers()
        {
            //Pretend we are getting a list of Customers from a repository.
            //Some go in the left List(Good Customers) some go in the Right List(Bad Customers).

            LeftList = new ObservableCollection<ListViewItem>();
            RightList = new ObservableCollection<ListViewItem>();

            var customers = GetCustomers();

            foreach (var customer in customers)
            {
                if (customer.Status == CustomerStatus.Good)
                {
                    LeftList.Add(new ListViewItem { Content = customer });
                }
                else
                {
                    RightList.Add(new ListViewItem{Content=customer });
                }
            }
        }

    private static IEnumerable<Customer> GetCustomers()
    {
        return new List<Customer>
                   {
                       new Customer {Name = "Jo Blogg", Status = CustomerStatus.Good},
                       new Customer {Name = "Rob Smith", Status = CustomerStatus.Good},
                       new Customer {Name = "Michel Platini", Status = CustomerStatus.Good},
                       new Customer {Name = "Roberto Baggio", Status = CustomerStatus.Good},
                       new Customer {Name = "Gio Surname", Status = CustomerStatus.Bad},
                       new Customer {Name = "Diego Maradona", Status = CustomerStatus.Bad}
                   };
    }
}

用户控件

         public partial class DualList:UserControl
        {
            public ObservableCollection<ListViewItem> LeftListCollection { get; set; }
            public ObservableCollection<ListViewItem> RightListCollection { get; set; }

            public DualList()
            {
                InitializeComponent();
            }

            public void Load(ObservableCollection<ListViewItem> leftListCollection, ObservableCollection<ListViewItem> rightListCollection)
            {
                LeftListCollection = leftListCollection;
                RightListCollection = rightListCollection;

                lvwLeft.ItemsSource = leftListCollection;
                lvwRight.ItemsSource = rightListCollection;

                EnableButtons();
            }
            public static DependencyProperty LeftTitleProperty = DependencyProperty.Register("LeftTitle",
                                                                                             typeof(string),
                                                                                             typeof(Label));

            public static DependencyProperty RightTitleProperty = DependencyProperty.Register("RightTitle",
                                                                                              typeof(string),
                                                                                              typeof(Label));


            public static DependencyProperty LeftListProperty = DependencyProperty.Register("LeftList",
                                                                                            typeof(ListView),
                                                                                            typeof(DualList));


            public static DependencyProperty RightListProperty = DependencyProperty.Register("RightList",
                                                                                            typeof(ListView),
                                                                                            typeof(DualList));
            public string LeftTitle
            {
                get { return (string)lblLeftTitle.Content; }
                set { lblLeftTitle.Content = value; }
            }
            public string RightTitle
            {
                get { return (string)lblRightTitle.Content; }
                set { lblRightTitle.Content = value; }
            }

            public ListView LeftList
            {
                get { return lvwLeft; }
                set { lvwLeft = value; }
            }
            public ListView RightList
            {
                get { return lvwRight; }
                set { lvwRight = value; }
            }

            private void EnableButtons()
            {
                if (lvwLeft.Items.Count > 0)
                {
                    btnMoveRight.IsEnabled = true;
                    btnMoveAllRight.IsEnabled = true;
                }
                else
                {
                    btnMoveRight.IsEnabled = false;
                    btnMoveAllRight.IsEnabled = false;
                }

                if (lvwRight.Items.Count > 0)
                {
                    btnMoveLeft.IsEnabled = true;
                    btnMoveAllLeft.IsEnabled = true;
                }
                else
                {
                    btnMoveLeft.IsEnabled = false;
                    btnMoveAllLeft.IsEnabled = false;
                }

                if (lvwLeft.Items.Count != 0 || lvwRight.Items.Count != 0) return;

                btnMoveLeft.IsEnabled = false;
                btnMoveAllLeft.IsEnabled = false;
                btnMoveRight.IsEnabled = false;
                btnMoveAllRight.IsEnabled = false;
            }

            private void MoveRight()
            {
                while (lvwLeft.SelectedItems.Count > 0)
                {
                    var selectedItem = (ListViewItem)lvwLeft.SelectedItem;
                    LeftListCollection.Remove(selectedItem);
                    RightListCollection.Add(selectedItem);
                }

                lvwRight.ItemsSource = RightListCollection;
                lvwLeft.ItemsSource = LeftListCollection;
                EnableButtons();
            }

            private void MoveAllRight()
            {
                while (lvwLeft.Items.Count > 0)
                {
                    var item = (ListViewItem)lvwLeft.Items[lvwLeft.Items.Count - 1];
                    LeftListCollection.Remove(item);
                    RightListCollection.Add(item);
                }

                lvwRight.ItemsSource = RightListCollection;
                lvwLeft.ItemsSource = LeftListCollection;
                EnableButtons();
            }

            private void MoveAllLeft()
            {
                while (lvwRight.Items.Count > 0)
                {
                    var item = (ListViewItem)lvwRight.Items[lvwRight.Items.Count - 1];
                    RightListCollection.Remove(item);
                    LeftListCollection.Add(item);
                }

                lvwRight.ItemsSource = RightListCollection;
                lvwLeft.ItemsSource = LeftListCollection;
                EnableButtons();
            }

            private void MoveLeft()
            {
                while (lvwRight.SelectedItems.Count > 0)
                {
                    var selectedCustomer = (ListViewItem)lvwRight.SelectedItem;
                    LeftListCollection.Add(selectedCustomer);
                    RightListCollection.Remove(selectedCustomer);
                }

                lvwRight.ItemsSource = RightListCollection;
                lvwLeft.ItemsSource = LeftListCollection;
                EnableButtons();
            }

            private void btnMoveLeft_Click(object sender, RoutedEventArgs e)
            {
                MoveLeft();
            }

            private void btnMoveAllLeft_Click(object sender, RoutedEventArgs e)
            {
                MoveAllLeft();
            }

            private void btnMoveRight_Click(object sender, RoutedEventArgs e)
            {
                MoveRight();
            }

            private void btnMoveAllRight_Click(object sender, RoutedEventArgs e)
            {
                MoveAllRight();
            }
        }

1 个答案:

答案 0 :(得分:1)

在查看了所有代码之后,我很清楚您使用的是旧的 WinForms 方式,而不是 WPF 方式。这不一定是坏事 - 它仍然有效,但维护起来非常困难。而不是利用WPF为我们提供的许多工具,例如数据绑定,命令,模板和依赖属性,您几乎可以使用事件处理程序连接所有内容并编写大量代码来维护UI。使用一些原始的XAML和代码,我构建了一个使用所有上述功能的示例。为了便于演示,我只是将其全部写在一个UserControl中,而不是将其分成Window。首先,XAML:

<Window x:Class="TestWpfApplication.DualList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApplication"
Title="DualList" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
    <ObjectDataProvider x:Key="Customers" ObjectType="{x:Type local:Customer}" MethodName="GetCustomers"/>
    <CollectionViewSource x:Key="GoodCustomers" Source="{StaticResource Customers}" Filter="GoodFilter"/>
    <CollectionViewSource x:Key="BadCustomers" Source="{StaticResource Customers}" Filter="BadFilter"/>

    <DataTemplate DataType="{x:Type local:Customer}">
        <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
</Window.Resources>
<Grid ShowGridLines="False">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Vertical" Grid.Column="0" Grid.Row="0">
        <Label Name="lblLeftTitle" Content="{Binding LeftHeader, FallbackValue=Available}"/>
        <ListView Name="lvwLeft" MinHeight="200"
                  ItemsSource="{Binding Source={StaticResource GoodCustomers}}"/>
    </StackPanel>
    <WrapPanel Grid.Column="1" Grid.Row="0"
               DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
        <Button Name="btnMoveRight" Command="{Binding MoveRightCommand}" 
                CommandParameter="{Binding ElementName=lvwLeft, Path=SelectedItem}"
                Content="&gt;" Width="25" Margin="0,35,0,0"/>
        <Button Name="btnMoveAllRight" Command="{Binding MoveAllRightCommand}" 
                CommandParameter="{Binding Source={StaticResource GoodCustomers}}"
                Content="&gt;&gt;" Width="25" Margin="0,05,0,0"/>
        <Button Name="btnMoveLeft" Command="{Binding MoveLeftCommand}" 
                CommandParameter="{Binding ElementName=lvwRight, Path=SelectedItem}"
                Content="&lt;" Width="25" Margin="0,25,0,0"/>
        <Button Name="btnMoveAllLeft" Command="{Binding MoveAllLeftCommand}" 
                CommandParameter="{Binding Source={StaticResource BadCustomers}}"
                Content="&lt;&lt;" Width="25" Margin="0,05,0,0"/>
    </WrapPanel>
    <StackPanel Orientation="Vertical" Grid.Column="2" Grid.Row="0">
        <Label Name="lblRightTitle" Content="{Binding RightHeader, FallbackValue=Selected}"/>
        <ListView Name="lvwRight" MinHeight="200"
                  ItemsSource="{Binding Source={StaticResource BadCustomers}}"/>
    </StackPanel>
</Grid>

从顶部开始,您将注意到的最重要的事情是我声明了ObjectDataProvider和两个CollectionViewSource对象。数据提供程序绑定到将创建默认客户列表的方法。视图来源(列出所有客户)列表并将其过滤到两个单独的列表中 - 一个用于好客户,另一个用于坏客户。这是通过CollectionViewSource.Filter属性完成的。

接下来,您将看到最初构建用户界面的用户界面,而不是连接事件处理程序,我已将按钮绑定到窗口上的命令。 ListView.ItemSource属性分别绑定在XAML中,绑定到GoodCustomersBadCustomers源。所有这些绑定都将删除大量的样板用户界面代码。现在让我们来看看代码隐藏:

public partial class DualList : Window
{
    public ICommand MoveRightCommand
    {
        get;
        set;
    }

    public ICommand MoveLeftCommand
    {
        get;
        set;
    }

    public ICommand MoveAllRightCommand
    {
        get;
        set;
    }

    public ICommand MoveAllLeftCommand
    {
        get;
        set;
    }

    public static DependencyProperty RightHeaderProperty =
        DependencyProperty.Register("RightHeader", typeof(string), typeof(DualList));

    public string RightHeader
    {
        get { return (string)GetValue(RightHeaderProperty); }
        set { SetValue(RightHeaderProperty, value); }
    }

    public static DependencyProperty LeftHeaderProperty =
        DependencyProperty.Register("LeftHeader", typeof(string), typeof(DualList));

    public string LeftHeader
    {
        get { return (string)GetValue(LeftHeaderProperty); }
        set { SetValue(LeftHeaderProperty, value); }
    }

    /// <summary>
    /// Default constructor-- set up RelayCommands.
    /// </summary>
    public DualList()
    {
        InitializeComponent();

        LeftHeader = "Good Customers";
        RightHeader = "Bad Customers";

        MoveRightCommand = new RelayCommand((o) => OnMoveRight((Customer)o), (o) => o != null);
        MoveLeftCommand = new RelayCommand((o) => OnMoveLeft((Customer)o), (o) => o != null);
        MoveAllRightCommand = new RelayCommand((o) => OnMoveAllRight((ListCollectionView)o), (o) => ((ListCollectionView)o).Count > 0);
        MoveAllLeftCommand = new RelayCommand((o) => OnMoveAllLeft((ListCollectionView)o), (o) => ((ListCollectionView)o).Count > 0);
    }

    /// <summary>
    /// Make this selected customer bad.
    /// </summary>
    private void OnMoveRight(Customer customer)
    {
        customer.Status = CustomerStatus.Bad;
        RefreshViews();
    }

    /// <summary>
    /// Make this selected customer good.
    /// </summary>
    private void OnMoveLeft(Customer customer)
    {
        customer.Status = CustomerStatus.Good;
        RefreshViews();
    }

    /// <summary>
    /// Make all customers bad.
    /// </summary>
    private void OnMoveAllRight(ListCollectionView customers)
    {
        foreach (Customer c in customers.SourceCollection)
            c.Status = CustomerStatus.Bad;
        RefreshViews();
    }

    /// <summary>
    /// Make all customers good.
    /// </summary>
    private void OnMoveAllLeft(ListCollectionView customers)
    {
        foreach (Customer c in customers.SourceCollection)
            c.Status = CustomerStatus.Good;
        RefreshViews();
    }

    /// <summary>
    /// Filters out any bad customers.
    /// </summary>
    private void GoodFilter(object sender, FilterEventArgs e)
    {
        Customer customer = e.Item as Customer;
        e.Accepted = customer.Status == CustomerStatus.Good;
    }

    /// <summary>
    /// Filters out any good customers.
    /// </summary>
    private void BadFilter(object sender, FilterEventArgs e)
    {
        Customer customer = e.Item as Customer;
        e.Accepted = customer.Status == CustomerStatus.Bad;
    }

    /// <summary>
    /// Refresh the collection view sources.
    /// </summary>
    private void RefreshViews()
    {
        foreach (object resource in Resources.Values)
        {
            CollectionViewSource cvs = resource as CollectionViewSource;
            if (cvs != null)
                cvs.View.Refresh();
        }
    }
}

从顶部开始,您会看到每个按钮的ICommand声明。我还添加了两个依赖项属性,表示列表的右侧和左侧标题(更改这些属性将自动更新UI中的标题)。然后,在构造函数中,我将每个命令连接到RelayCommand(由Josh Smith创建),它只是让我指定两个委托 - 一个用于执行命令,另一个用于控制命令何时可以执行。您可以看到,而不是在列表之间移动项目,我只是更改列表被过滤的项目的属性。因此,为了移动项目,我将客户状态更改为良好。这是分离UI和业务逻辑的示例:UI反映了对基础项所做的更改,但不会自行进行更改。

每个命令的逻辑应该相当容易理解 - 将所有客户移到良好的列表中,我们只是遍历每个客户,将他们的Status设置为好。冲洗并重复其他命令。请注意,我们必须更新我们的CollectionViewSource个对象以进行过滤器更新。否则不会显示任何更改。

所以,总结一下:

  • 不要写一堆代码隐藏来维护你的UI,而是使用数据绑定。 CollectionViewSourceObjectDataProvider可用于按您希望的方式过滤和显示数据。在您的方案中,我有一个列表可以根据客户状态进行过滤,而不是管理两个列表。
  • 不要使用事件处理程序来设置UI逻辑,使用命令。它们增加了封装并允许自动更新UI。
  • 使用依赖项属性和绑定允许用户自定义列表标题。