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=">>>" /> 42 <Button 43 Height="50" 44 Content="<<<" /> 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 }
测试一下


浙公网安备 33010602011771号