Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 740767
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 14, 20262026-05-14T08:33:14+00:00 2026-05-14T08:33:14+00:00

I am trying to write a Dual List usercontrol in wpf. I am new

  • 0

I am trying to write a Dual List usercontrol in wpf.

I am new to wpf and I am finding it quite difficult.
This is something I have put together in a couple of hours.It’s not that good but a start.

I would be extremely grateful if somebody with wpf experience could improve it.
The aim is to simplify the usage as much as possible

I am kind of stuck.
I would like the user of the DualList Control to be able to set up headers how do you do that.
Do I need to expose some dependency properties in my control?

At the moment when loading the user has to pass a ObservableCollection is there a better way?

Could you have a look and possibly make any suggestions with some code?

Thanks a lot!!!!!

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>

Client

       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}
                   };
    }
}

UserControl

         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 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-14T08:33:15+00:00Added an answer on May 14, 2026 at 8:33 am

    After looking over all of your code, it is clear to me that you are doing this the old WinForms way, rather than the WPF way. This isn’t necessarily bad– it still works, but it will be quite difficult to maintain. Rather than taking advantage of the many tools WPF gives us, such as data-binding, commands, templates, and dependency properties, you are pretty much wiring everything up with event handlers and writing a lot of code to maintain the UI. Using some of your original XAML and code, I have constructed a example that uses all of the aforementioned features. Rather than separate it into a UserControl, I have simply written it all in one Window for ease of demonstration. First, the 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>
    

    Starting from the top, the most important thing you will notice is that I am declaring an ObjectDataProvider and two CollectionViewSource objects. The data provider is bound to a method that will create your default customer list. The view sources take that list (of all customers) and filters them into two separate lists- one for good customers, and the other for bad customers. This is done through the CollectionViewSource.Filter property.

    Next, you will see the user interface as you originally constructed it, but rather than wire up event handlers, I have bound the buttons to commands on the window. The ListView.ItemSource property is bound in the XAML, to the GoodCustomers and BadCustomers sources, respectively. All of these bindings will remove a good chunk of your boilerplate user-interface code. Now let’s take a look at the code-behind:

    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();
            }
        }
    }
    

    Starting from the top, you will see an ICommand declaration for each button. I have also added two dependency properties that represent the right and left headers for your lists (changing these properties will automatically update the headers in the UI). Then, in the constructor, I hook up each command to a RelayCommand (created by Josh Smith), which simply lets me specify two delegates- one for when the command is executed, another that controls when the command can be executed. You can see that rather than moving items in between lists, I am simply changing the property on the item by which the list is filtered. So to move an item left, I change the customer status to good. This is an example of separation of UI and business logic: the UI reflects changes made to the underlying items, but does not make the changes itself.

    The logic for each command should be fairly easy to understand- to move all customers to the good list, we simply iterate over each customer, setting their Status to good. Rinse and repeat for the other commands. Note that we must update our CollectionViewSource objects to make the filter update. Otherwise no changes would be shown.

    So, in summary:

    • Don’t write a bunch of code-behind to maintain your UI, use data-binding instead. CollectionViewSource and ObjectDataProvider can be used to filter and display your data the way you want it to. In your scenario, rather than manage two lists, I have a single list that gets filtered based on the customer status.
    • Don’t use event handlers to set up UI logic, use commands. They increase encapsulation and allow for automatic updates to your UI.
    • Use dependency properties and binding to allow the user to customize your list headers.
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Trying to write this small program to help me in my Stats class, everything
I'm trying to write a program that change default SIM card on my dual-sim
I've been spending quite alot of time recently trying to learn XAML/C#/WPF/Silverlight, trying to
I referred to this article http://www.codeproject.com/KB/security/DotNetCrypto.aspx and I am trying write an encrypted string
I'm trying write a query to find records which don't have a matching record
I'm trying write a program that takes a list of names, sorts those names,
I have been trying write a Mutually Exclusive CheckBox. There are two checkBoxes in
Hi im trying to write a lockless list i got the adding part working
Trying to write a GLOBAL CBT HOOK, this is My code, but my hooking
Trying to write a Lua script for Scite (something like lua-users wiki: Scite Comment

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.