WPF 使用UserControl制作一个简单的穿梭框

首先看下效果

 首先创建一个UserControl

放两个ListBox进去

然后在UserControl的.CS文件中创建两个依赖属性 并绑定到ListBox的ItemsSouce,绑定可以有多种方法,可以在xaml里面指定DataContext,也可以在后台代码指定DataContext=this,也可以用关系绑定,这里用的关系绑定

然后写一个ListBox的样式模板,在里面放一个Button,给Button的双击事件创建一个处理代码,就完成了

UserControl 界面代码

 1 <UserControl
 2     x:Class="ShuttleBox穿梭框.ShuttleBox"
 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 5     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 6     xmlns:local="clr-namespace:ShuttleBox穿梭框"
 7     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 8     d:DesignHeight="450"
 9     d:DesignWidth="800"
10     mc:Ignorable="d">
11     <UserControl.Resources>
12         <!--重写ListBoxItem的样式 放一个Button进去 给双击事件给个处理方法-->
13         <Style TargetType="ListBoxItem">
14             <Setter Property="Template">
15                 <Setter.Value>
16                     <ControlTemplate TargetType="ListBoxItem">
17                         <Button
18                             MouseDoubleClick="Button_MouseDoubleClick">
19                             <ContentPresenter />
20                         </Button>
21                     </ControlTemplate>
22                 </Setter.Value>
23             </Setter>
24         </Style>
25     </UserControl.Resources>
26     <Grid>
27         <Grid.ColumnDefinitions>
28             <ColumnDefinition Width="5*" />
29             <ColumnDefinition Width="*" />
30             <ColumnDefinition Width="5*" />
31         </Grid.ColumnDefinitions>
32         <!--创建2个ListBox 把ItemsSouce绑定到依赖属性上面 这样就能在外部创建绑定了-->
33         <ListBox
34             Grid.Column="0"
35             ItemsSource="{Binding Path=OriginList, RelativeSource={RelativeSource AncestorType={x:Type local:ShuttleBox}}}" />
36         <StackPanel
37             Grid.Column="1"
38             Orientation="Vertical">
39             <Button
40                 Height="50"
41                 Content="&gt;&gt;&gt;" />
42             <Button
43                 Height="50"
44                 Content="&lt;&lt;&lt;" />
45         </StackPanel>
46         <ListBox
47             x:Name="targetListBox"
48             Grid.Column="2"
49             ItemsSource="{Binding Path=TargetList, RelativeSource={RelativeSource AncestorType={x:Type local:ShuttleBox}}}" />
50     </Grid>
51 </UserControl>

UserControl 后台代码

 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 using System.Windows;
 8 using System.Windows.Controls;
 9 using System.Windows.Data;
10 using System.Windows.Documents;
11 using System.Windows.Input;
12 using System.Windows.Media;
13 using System.Windows.Media.Imaging;
14 using System.Windows.Navigation;
15 using System.Windows.Shapes;
16 
17 
18 namespace ShuttleBox穿梭框
19 {
20     /// <summary>
21     /// ShuttleBox.xaml 的交互逻辑
22     /// </summary>
23     public partial class ShuttleBox : UserControl
24     {
25         // Using a DependencyProperty as the backing store for OriginList.  This enables animation, styling, binding, etc...
26         public static readonly DependencyProperty OriginListProperty =
27             DependencyProperty.Register("OriginList", typeof(IEnumerable), typeof(ShuttleBox), new PropertyMetadata(default));
28 
29         // Using a DependencyProperty as the backing store for TargetList.  This enables animation, styling, binding, etc...
30         public static readonly DependencyProperty TargetListProperty =
31             DependencyProperty.Register("TargetList", typeof(IEnumerable), typeof(ShuttleBox), new PropertyMetadata(default));
32 
33         public IEnumerable OriginList
34         {
35             get { return (IEnumerable)GetValue(OriginListProperty); }
36             set { SetValue(OriginListProperty, value); }
37         }
38 
39         public IEnumerable TargetList
40         {
41             get { return (IEnumerable)GetValue(TargetListProperty); }
42             set { SetValue(TargetListProperty, value); }
43         }
44 
45         public ShuttleBox()
46         {
47             InitializeComponent();
48 
49             //通过把DataContext指定为自身的 好像会有一点问题。。先不用这个
50             //DataContext = this;
51         }
52 
53         private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
54         {
55             //初始的时候 目标列表可能为空 
56             if (TargetList == null)
57             {
58                 TargetList = new List<object>();
59             }
60 
61             //选择项  写的有问题,更改的时候,ViewModel的属性没有更改
62             var content = (((sender as Button).Content) as ContentPresenter).Content;
63 
64             var list1 = OriginList.OfType<object>().ToList();
65             var list2 = TargetList.OfType<object>().ToList();
66 
67             //查看当前选择项是在那个列表里面
68             var flag = list1.Contains(content);
69             if (flag)
70             {
71                 list1.Remove(content);
72                 list2.Add(content);
73             }
74             else
75             {
76                 list2.Remove(content);
77                 list1.Add(content);
78             }
79 
80             OriginList = list1;//绑定原始列表
81             TargetList = list2;//绑定目标列表
82         }
83     }
84 }

Window 界面代码

 1 <Window
 2     x:Class="ShuttleBox穿梭框.MainWindow"
 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 5     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 6     xmlns:local="clr-namespace:ShuttleBox穿梭框"
 7     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 8     Title="MainWindow"
 9     Width="800"
10     Height="450"
11     mc:Ignorable="d">
12     <Window.DataContext>
13         <local:ViewModel />
14     </Window.DataContext>
15 
16     <Grid>
17         <local:ShuttleBox
18             x:Name="list"
19             OriginList="{Binding List1}"
20             TargetList="{Binding List2}" />
21     </Grid>
22 </Window>

Window后台代码

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Globalization;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 using System.Windows;
 8 using System.Windows.Controls;
 9 using System.Windows.Data;
10 using System.Windows.Documents;
11 using System.Windows.Input;
12 using System.Windows.Media;
13 using System.Windows.Media.Imaging;
14 using System.Windows.Navigation;
15 using System.Windows.Shapes;
16 
17 namespace ShuttleBox穿梭框
18 {
19     /// <summary>
20     /// MainWindow.xaml 的交互逻辑
21     /// </summary>
22     public partial class MainWindow : Window
23     {
24         public MainWindow()
25         {
26             InitializeComponent();
27         }
28     }
29 
30     public class ViewModel
31     {
32         public List<string> List1 { get; set; }
33 
34         public List<string> List2 { get; set; }
35 
36         public ViewModel()
37         {
38             List1 = new List<string>()
39             {
40                 "A",
41                 "B",
42                 "C",
43                 "D",
44                 "E",
45             };
46         }
47     }
48 }

 

 

前面的UserControl的代码有问题,没有更新ViewModel里面的属性,因为改变了属性的引用

实际上应该这么做

 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 using System.Windows;
 8 using System.Windows.Controls;
 9 using System.Windows.Data;
10 using System.Windows.Documents;
11 using System.Windows.Input;
12 using System.Windows.Media;
13 using System.Windows.Media.Imaging;
14 using System.Windows.Navigation;
15 using System.Windows.Shapes;
16 
17 namespace ShuttleBox穿梭框
18 {
19     /// <summary>
20     /// ShuttleBox.xaml 的交互逻辑
21     /// </summary>
22     public partial class ShuttleBox : UserControl
23     {
24         // Using a DependencyProperty as the backing store for OriginList.  This enables animation, styling, binding, etc...
25         public static readonly DependencyProperty OriginListProperty =
26             DependencyProperty.Register("OriginList", typeof(IEnumerable), typeof(ShuttleBox), new PropertyMetadata(default));
27 
28         // Using a DependencyProperty as the backing store for TargetList.  This enables animation, styling, binding, etc...
29         public static readonly DependencyProperty TargetListProperty =
30             DependencyProperty.Register("TargetList", typeof(IEnumerable), typeof(ShuttleBox), new PropertyMetadata(default));
31 
32         public IEnumerable OriginList
33         {
34             get { return (IEnumerable)GetValue(OriginListProperty); }
35             set { SetValue(OriginListProperty, value); }
36         }
37 
38         public IEnumerable TargetList
39         {
40             get { return (IEnumerable)GetValue(TargetListProperty); }
41             set { SetValue(TargetListProperty, value); }
42         }
43 
44         public ShuttleBox()
45         {
46             InitializeComponent();
47 
48             //通过把DataContext指定为自身的 好像会有一点问题。。先不用这个
49             //DataContext = this;
50         }
51 
52         private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
53         {
54             //获取绑定的属性的数据源,一般集合类都会实现IList接口,所以直接转换为IList
55             var list1 = (IList)GetValue(OriginListProperty);
56             var list2 = (IList)GetValue(TargetListProperty);
57 
58             //选择项
59             var content = (((sender as Button).Content) as ContentPresenter).Content;
60 
61             var flag = list1.Contains(content);
62 
63             if (flag)
64             {
65                 list1.Remove(content);
66                 list2.Add(content);
67             }
68             else
69             {
70                 list2.Remove(content);
71                 list1.Add(content);
72             }
73             var ss = DataContext;
74         }
75     }
76 }

然后把VM里面的属性集合改为ObservableCollection 这样在控件里面更改了数据,就能实现通知UI了

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Collections.ObjectModel;
 4 using System.Globalization;
 5 using System.Linq;
 6 using System.Text;
 7 using System.Threading.Tasks;
 8 using System.Windows;
 9 using System.Windows.Controls;
10 using System.Windows.Data;
11 using System.Windows.Documents;
12 using System.Windows.Input;
13 using System.Windows.Media;
14 using System.Windows.Media.Imaging;
15 using System.Windows.Navigation;
16 using System.Windows.Shapes;
17 
18 namespace ShuttleBox穿梭框
19 {
20     /// <summary>
21     /// MainWindow.xaml 的交互逻辑
22     /// </summary>
23     public partial class MainWindow : Window
24     {
25         public MainWindow()
26         {
27             InitializeComponent();
28         }
29     }
30 
31     public class ViewModel
32     {
33         public ObservableCollection<string> List1 { get; set; }
34 
35         public ObservableCollection<string> List2 { get; set; }
36 
37         public ViewModel()
38         {
39             List1 = new ObservableCollection<string>()
40             {
41                 "A",
42                 "B",
43                 "C",
44                 "D",
45                 "E",
46             };
47             List2 = new ObservableCollection<string>();
48         }
49     }
50 }

测试一下

 

posted @ 2021-11-25 23:45  只吃肉不喝酒  阅读(922)  评论(0编辑  收藏  举报