wpf中UserControl的几种绑定方式

我们经常会抽取一些可重用的控件,某个属性是否需要重用,直接决定了这个属性的绑定方式。

1、完全不可重用的控件

有一些与业务强相关的控件,它们的属性完全来自ViewModel,越是相对复杂的控件,越容易这样。比如:

// ChooseUc.xaml
<UserControl>
    <StackPanel Orientation="Horizontal">
        <Label Content="选择一个水果: "/>
        <ComboBox ItemsSource="{Binding Fruits}"/>
    </StackPanel>
</UserControl>

使用的时候直接 <my:ChooseUc /> 即可直接绑定到ViewModel里的 List<Fruit> Fruits ,不用做额外的工作。好处是特别方便,代价是与vm完全耦合。

2、完全可重用的控件

类似的控件多了,就能抽出一些完全可重用的控件,这些控件与业务无关。为了实现这种重用性,要做到:

  1. 抽出所有可变的属性,定义在控件内部
  2. 绑定控件内定义的这些属性
  3. 外部使用时,再将这些属性与vm绑定

具体如下:

// ChooseUc.xaml
<UserControl>
    <StackPanel x:Name="root" Orientation="Horizontal">
        <Label Content="{Binding Header}"/>
        <ComboBox ItemsSource="{Binding Items}"/>
    </StackPanel>
</UserControl>

相应的cs代码为:

// ChooseUc.xaml.cs
public ChooseUc() {
    InitializeComponent();
    root.DataContext = this; // 这句很关键!
}

public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(IEnumerable), typeof(ChooseUc));
public IEnumerable Items {
    get { return (IEnumerable)GetValue(ItemsProperty); }
    set { SetValue(ItemsProperty, value); }
}

//HeaderProperty类似,此处省略

使用的时候为:

<my:ChooseUc Header="{Binding FruitHeader}" Items="{Binding Fruits}" />

特别注意 root.DataContext = this;这一句把内部的控件与外界隔离了,内部事实上已经看不到ViewModel了,只能看到内部定义的属性(Header、Items之类的)。麻烦一些,但好处是可以适用于1个标签+1个下拉框的任何场景,复用性高。

缺点是,在级联的自定义控件里,简直是个噩梦。设想有3个UserControl:C>B>A (C包含B、B包含A)。只有C有对应的vm,这种情况下B要包含A的所有属性。实际情况是,B要包含所有子控件的所有属性,这无疑是让人郁闷的!

好在多数情况下我们并不需要级联嵌套自定义控件,而且我们也可以放弃一些复用性,以获得默认绑定vm的便利。

3、部分可重用的控件

还有一类情况就是控件部分可重用,考虑这样一个场景:用户可以选择2个水果,这时Fruits可以直接绑到vm里,但SelectedFruit需要分别绑定:

// ChooseUc.xaml
<UserControl x:Name="uc">
    <StackPanel Orientation="Horizontal">
        <Label Content="选择一个水果: "/>
        <ComboBox ItemsSource="{Binding Fruits}" SelectedItem="{Binding SelectedFruit, ElementName=uc}"/>
    </StackPanel>
</UserControl>

// 类似的,ChooseUc.xaml.cs里定义SelectedFruit依赖属性

使用的时候为:

<StackPanel>
    <my:ChooseUc SelectedFruit="{Binding Fruit1}" />
    <my:ChooseUc SelectedFruit="{Binding Fruit2}" />
</StackPanel>

这种情况下,即使是级联,Fruits也不需要重复定义,又获得了SelectedFruit的灵活性。这里的关键是:只把需要复用的属性,绑定到控件内部,其他属性继承vm就好

4、小结

实际开发的过程中,大部分的情况是1+3,即完全不重用+部分重用的控件。即使遇到完全重用的控件,也不大会形成级联。

转载于:https://www.cnblogs.com/AlexanderYao/p/5534952.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF UserControl可以分为两种情况: 1. UserControl 内部的元素UserControl 的 XAML ,可以直接使用 Binding 进行。例如, UserControl 内部 TextBox 的 Text 属性: ```xaml <UserControl x:Class="WpfApp1.MyUserControl" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <TextBox Text="{Binding MyText}" /> </Grid> </UserControl> ``` 在 UserControl 的代码,需要义一个 DependencyProperty 或者一个普通的属性来实现。例如,义一个 DependencyProperty: ```csharp public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(string), typeof(MyUserControl), new PropertyMetadata(string.Empty)); public string MyText { get { return (string)GetValue(MyTextProperty); } set { SetValue(MyTextProperty, value); } } ``` 2. UserControl 外部元素 在使用 UserControl 的地方,可以使用 ElementName UserControl 内部的元素。例如: ```xaml <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1" Title="MainWindow" Height="450" Width="800"> <StackPanel> <local:MyUserControl x:Name="myUserControl" /> <TextBlock Text="{Binding ElementName=myUserControl, Path=MyText}" /> </StackPanel> </Window> ``` 在使用 UserControl 的地方,需要义一个 ViewModel,并且将 ViewModel 与 UserControl 进行。例如: ```xaml <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:MainViewModel /> </Window.DataContext> <StackPanel> <local:MyUserControl MyText="{Binding Text}" /> </StackPanel> </Window> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值