WPF UserControl DependencyProperty在XAML中使用或通过绑定

时间:2018-07-01 18:01:53

标签: c# wpf xaml

我想要一个通用的UserControl,在其中可以通过直接在XAML中设置其值或将其绑定到某些模型属性来设置属性。

就像TextBlock的Text属性一样。

现在,我只拥有简单的简单UserControl,它具有单个DependencyProperty TxT和绑定到其上的TextBlock Text属性。没有其他代码。

如果我在主窗口的XAML中设置了TxT,它将无法正常工作,则绑定有效。

如果我将PropertyChangedCallback添加到该DependencyProperty,它也可以在XAML中使用。

所以问题是,如果我希望能够直接在XAML中设置每个属性,是否必须对每个属性都设置PropertyChangedCallback?

这对我来说还不清楚,大多数都没有提及,但这也迫使我添加内部控件名称来更改它们在PropertyChangedCallback中的值。

代码在下面。

可以通过其他方式完成吗?

MainWindow

<Window
    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:WpfAppDpBare" xmlns:Model="clr-namespace:WpfAppDpBare.Model" x:Class="WpfAppDpBare.MainWindow"
    Background="CadetBlue"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
<Window.DataContext>
    <Model:MainModel/>
</Window.DataContext>
<Grid>
    <local:UserControlSample TxT="DIRECT TXT" HorizontalAlignment="Center" VerticalAlignment="Center" Height="125" Width="125" Margin="10,34,659,262"/>
    <TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Direct" VerticalAlignment="Top" FontSize="14" FontWeight="Bold"/>
    <TextBlock HorizontalAlignment="Left" Margin="203,10,0,0" TextWrapping="Wrap" Text="Binding" VerticalAlignment="Top" FontSize="14" FontWeight="Bold"/>
    <local:UserControlSample DataContext="{Binding UCData}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="125" Width="125" Margin="203,34,466,262"/>
</Grid>

public partial class MainWindow:Window {
    public MainWindow() {
        InitializeComponent();
        }
    }

UserControl

<UserControl x:Class="WpfAppDpBare.UserControlSample"
         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:WpfAppDpBare"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800" Background="White">
<Grid>
    <TextBlock TextWrapping="Wrap" Text="{Binding TxT,FallbackValue=...,TargetNullValue=...}" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="Bold"/>

</Grid>

 public partial class UserControlSample:UserControl {
    public UserControlSample() {
        InitializeComponent();
        }

    public string TxT {
        get { return (string)GetValue(TxTProperty); }
        set { SetValue(TxTProperty, value); }
        }

    // Using a DependencyProperty as the backing store for TxT.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TxTProperty =
        DependencyProperty.Register("TxT", typeof(string), typeof(UserControlSample), new PropertyMetadata());

    }

模型

  public class MainModel:ViewModelBase {

    /// <summary>
    /// The <see cref="UCData" /> property's name.
    /// </summary>
    public const string UCDataPropertyName = "UCData";

    private UCModel uCModel = null;

    /// <summary>
    /// Sets and gets the UCData property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public UCModel UCData {
        get {
            return uCModel;
            }

        set {
            if(uCModel == value) {
                return;
                }

            uCModel = value;
            RaisePropertyChanged(UCDataPropertyName);
            }
        }

    public MainModel() {
        UCData = new UCModel() { TxT = "BINDING TXT" };
        }

    }

public class UCModel:ViewModelBase {

    /// <summary>
    /// The <see cref="TxT" /> property's name.
    /// </summary>
    public const string TxTPropertyName = "TxT";

    private string _TxT = null;

    /// <summary>
    /// Sets and gets the TxT property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public string TxT {
        get {
            return _TxT;
            }

        set {
            if(_TxT == value) {
                return;
                }

            _TxT = value;
            RaisePropertyChanged(TxTPropertyName);
            }
        }

    }

完整的裸项目https://wetransfer.com/downloads/199f3db5d183e64cf9f20db4225d4c9820180702001102/f4f61b

sample

如您在项目绑定工程中所看到的,直接属性文本不是。

我希望所有这些内容都包含在usercontrol中,所以我可以在xaml中设置usercontrol属性值或将其绑定到主窗口xaml或代码中,而无需另外添加。

1 个答案:

答案 0 :(得分:0)

您没有将TextBlock的Text属性绑定到UserControl的TxT属性。

设置绑定的RelativeSource

<TextBlock Text="{Binding TxT,
                  RelativeSource={RelativeSource AncestorType=UserControl}, ...}" .../>

或将x:Name分配给UserControl并使用ElementName绑定。


然后,而不是通过以下方式设置UserControl的DataContext:

<local:UserControlSample DataContext="{Binding UCData}" .../>

绑定其TxT属性:

<local:UserControlSample TxT="{Binding UCData.TxT}" .../>

编辑:为了直接绑定到对象在其DataContext中的属性,

<local:UserControlSample DataContext="{Binding UCData}" .../>

您根本不需要在UserControl中声明任何属性。删除TxT依赖项属性声明,并直接绑定UserControl的XAML中的元素,就像已经做的那样:

<TextBlock Text="{Binding TxT, ...}"/>

但是请注意,这不是UserControl通常的工作方式。现在,您的确依赖于特定的视图模型类型,并且不能与其他视图模型一起使用。