wpf mvvm框架中,自定义控件中command绑定和某个页面button元素绑定的区别

1.常用页面button直接绑定command,触发viewModel中的指定cmd:

 绑定方式:Command="{Binding ViewCmd}"

2.在listbox中添加了button按钮:

当直接绑定Command="{Binding ViewCmd}"是点击按钮,不会触发ViewModel中的ViewCmd,

需要相对源的绑定:Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=DataContext.GetBtnTextCmd}"

  • Command=: 这个属性用于将按钮的命令与 ViewModel 中的一个 ICommand 属性进行绑定。
  • Binding: 这个关键字表示要进行数据绑定。
  • RelativeSource: 这个属性指定了绑定源对象的相对位置。
  • FindAncestor: 这个值表示要在视觉树中向上查找,以找到一个指定类型的父级元素。
  • AncestorType=ListBox: 这个值表示要查找 ListBox 类型的父级元素。
  • Path=DataContext.GetBtnTextCmd: 这个值表示要绑定的属性路径。它指定了要从 ListBox 的 DataContext(即 ViewModel)中获取的 ICommand 属性的名称。

 两者间的区别:

  • Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=DataContext.GetBtnTextCmd}" 是在 ListBox 控件内部的 Button 按钮中进行的数据绑定。它会将按钮的命令与 ListBox 控件的父级元素(即 ViewModel)中的 GetBtnTextCmd 属性进行绑定,这样按钮被点击时,会调用 GetBtnTextCmd 命令所在 ViewModel 中的相应方法。

  • Command="{Binding LoadRepeatViewCmd}" 是在某个元素(例如 Button、MenuItem 等)的属性中进行的数据绑定。它会将该元素的命令与当前元素所在的 DataContext(即 ViewModel)中的 LoadRepeatViewCmd 属性进行绑定,这样当该元素被点击时,会调用 LoadRepeatViewCmd 命令所在 ViewModel 中的相应方法。

因此,两者的主要区别在于绑定的对象不同。第一个绑定是在 ListBox 中的 Button 中进行的,而第二个绑定是在某个元素的属性中进行的。另外,第一个绑定使用了相对源绑定,以便查找 ListBox 的 DataContext,而第二个绑定没有使用相对源绑定,因此默认使用的是当前元素所在的 DataContext。

好的,下面是一个 WPF MVVM 框架搭建并使用自定义控件的工程事例: 1. 创建一个 WPF 应用程序项目。 2. 在项目添加一个名为 Models 的文件夹,并在其添加一个名为 Student.cs 的类,该类包含学生的姓名和年龄属性: ```csharp namespace WpfMvvmDemo.Models { public class Student { public string Name { get; set; } public int Age { get; set; } } } ``` 3. 在项目添加一个名为 ViewModels 的文件夹,并在其添加一个名为 MainViewModel.cs 的类,该类包含一个名为 Students 的可观察集合属性,用于存储学生对象,并在构造函数初始化该集合: ```csharp using System.Collections.ObjectModel; using WpfMvvmDemo.Models; namespace WpfMvvmDemo.ViewModels { public class MainViewModel { public ObservableCollection<Student> Students { get; set; } public MainViewModel() { Students = new ObservableCollection<Student> { new Student { Name = "张三", Age = 18 }, new Student { Name = "李四", Age = 19 }, new Student { Name = "王五", Age = 20 } }; } } } ``` 4. 在项目添加一个名为 Controls 的文件夹,并在其添加一个名为 StudentControl.xaml 的自定义控件。该控件包含一个 TextBlock 控件和一个 Button 控件,用于显示学生的姓名和年龄,并提供一个名为 DeleteCommand 的依赖属性,以便在删除按钮被点击时执行删除操作: ```xaml <UserControl x:Class="WpfMvvmDemo.Controls.StudentControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfMvvmDemo.Controls" mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="200"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Name}" Margin="5" /> <Button Grid.Column="1" Content="删除" Margin="5" Command="{Binding DeleteCommand}" /> </Grid> </UserControl> ``` 5. 在 StudentControl.xaml.cs ,定义 DeleteCommand 依赖属性,并在构造函数为该属性设置默认值: ```csharp using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace WpfMvvmDemo.Controls { public partial class StudentControl : UserControl { public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(StudentControl), new PropertyMetadata(null)); public ICommand DeleteCommand { get { return (ICommand)GetValue(DeleteCommandProperty); } set { SetValue(DeleteCommandProperty, value); } } public StudentControl() { InitializeComponent(); DeleteCommand = new RelayCommand(Delete); } private void Delete(object parameter) { // 执行删除操作 } } } ``` 6. 在项目添加一个名为 Commands 的文件夹,并在其添加一个名为 RelayCommand.cs 的类,该类实现了 ICommand 接口,用于在控件执行命令: ```csharp using System; using System.Windows.Input; namespace WpfMvvmDemo.Commands { public class RelayCommand : ICommand { private readonly Action<object> _execute; private readonly Predicate<object> _canExecute; public RelayCommand(Action<object> execute, Predicate<object> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute?.Invoke(parameter) ?? true; } public void Execute(object parameter) { _execute(parameter); } } } ``` 7. 在项目添加一个名为 Converters 的文件夹,并在其添加一个名为 AgeToStringConverter.cs 的类,该类实现了 IValueConverter 接口,用于将学生的年龄转换为字符串: ```csharp using System; using System.Globalization; using System.Windows.Data; namespace WpfMvvmDemo.Converters { public class AgeToStringConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is int age) { return $"{age} 岁"; } return null; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ``` 8. 在 MainWindow.xaml ,使用 StudentControl 自定义控件,将 ItemsControl 控件绑定到 MainViewModel 的 Students 属性,并使用 AgeToStringConverter 将学生的年龄转换为字符串: ```xaml <Window x:Class="WpfMvvmDemo.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfMvvmDemo.Views" xmlns:viewModel="clr-namespace:WpfMvvmDemo.ViewModels" xmlns:controls="clr-namespace:WpfMvvmDemo.Controls" xmlns:converters="clr-namespace:WpfMvvmDemo.Converters" xmlns:commands="clr-namespace:WpfMvvmDemo.Commands" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <viewModel:MainViewModel /> </Window.DataContext> <Window.Resources> <converters:AgeToStringConverter x:Key="AgeToStringConverter" /> </Window.Resources> <Grid> <ItemsControl ItemsSource="{Binding Students}"> <ItemsControl.ItemTemplate> <DataTemplate> <controls:StudentControl> <controls:StudentControl.DataContext> <viewModel:StudentViewModel Name="{Binding Name}" Age="{Binding Age}" DeleteCommand="{Binding DataContext.DeleteStudentCommand, RelativeSource={RelativeSource AncestorType=Window}}" /> </controls:StudentControl.DataContext> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Margin="5" /> <TextBlock Text="{Binding Age, Converter={StaticResource AgeToStringConverter}}" Margin="5" /> </StackPanel> </controls:StudentControl> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid> </Window> ``` 9. 在项目添加一个名为 StudentViewModel.cs 的类,该类用于将学生对象转换为可供 StudentControl 使用的视图模型,并包含一个名为 DeleteCommand 的命令,用于删除该学生: ```csharp using System.Windows.Input; using WpfMvvmDemo.Commands; namespace WpfMvvmDemo.ViewModels { public class StudentViewModel { public string Name { get; set; } public int Age { get; set; } public ICommand DeleteCommand { get; set; } public StudentViewModel(string name, int age, ICommand deleteCommand) { Name = name; Age = age; DeleteCommand = deleteCommand; } } } ``` 10. 在 MainViewModel.cs ,添加一个名为 DeleteStudentCommand 的命令,用于删除选定的学生: ```csharp using System.Collections.ObjectModel; using System.Windows.Input; using WpfMvvmDemo.Commands; using WpfMvvmDemo.Models; namespace WpfMvvmDemo.ViewModels { public class MainViewModel { public ObservableCollection<Student> Students { get; set; } public ICommand DeleteStudentCommand { get; set; } public MainViewModel() { Students = new ObservableCollection<Student> { new Student { Name = "张三", Age = 18 }, new Student { Name = "李四", Age = 19 }, new Student { Name = "王五", Age = 20 } }; DeleteStudentCommand = new RelayCommand(DeleteStudent); } private void DeleteStudent(object parameter) { if (parameter is Student student) { Students.Remove(student); } } } } ``` 这就是一个 WPF MVVM 框架搭建并使用自定义控件的工程事例。通过这个例子,你可以学习到如何使用自定义控件和视图模型,实现更加灵活的界面设计和命令操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白话Learning

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值