【问题标题】:WPF UserControl DependencyProperty use in XAML or by bindingWPF UserControl DependencyProperty 在 XAML 中使用或通过绑定
【发布时间】:2018-07-04 11:49:24
【问题描述】:

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

就像 TextBlock Text 属性一样。

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

如果我在主窗口的 XAML 中设置 TxT,它将不起作用,绑定有效。

如果我将 PropertyChangedCallback 添加到该 DependencyProperty 它也适用于 XAML。

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

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

代码如下。

可以用其他方法吗?

主窗口

<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 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

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

我希望它全部包含在用户控件中,所以我要么在 xaml 中设置用户控件属性值,要么绑定到它,而不在主窗口 xaml 或代码中添加其他内容。

【问题讨论】:

  • @ASh 和stackoverflow.com/questions/4368808/…基本一样,是你能做的最简单的代码,如果我的描述不够我可以提供一个裸项目。
  • 那个解决了。如果你的不工作,那么smth是不同的
  • 另一个stackoverflow.com/questions/50835495/… 帖子我展示了使用自定义依赖属性创建用户自定义控件以及如何在 xaml 中进行设置。通过标准绑定您尝试绑定到的模型,文本值可以/也应该完全有效...看看该链接是否有助于理解这些步骤...
  • 显示您的代码,否则我们无法帮助您。也就是说,“如果我希望能够直接在 XAML 中设置它,是否必须为每个属性设置 PropertyChangedCallback?” - 不,绝对不是。有没有这样的回调并不重要。

标签: c# wpf xaml


【解决方案1】:

您没有将 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 通常的工作方式。您的现在确实依赖于特定的视图模型类型,并且不能与其他视图模型重用。

【讨论】:

  • 这不是真的,我正在将 Text 属性绑定到 Txt,正如您在问题代码示例和可用项目文件中看到的那样,如果我像您建议的那样更改它或使用 ElementName 然后直接设置属性会起作用,但绑定不会。它需要在这两种情况下都起作用。
  • @Programista:您将TxT 依赖属性设置为“DIRECT TXT”,但您没有在某处显示此值。显示的值是UCModelTxT 属性的值。
  • @Programista 有两个 TxT 属性,一个在 UserControl 中,另一个在视图模型中。如果您为这些属性使用不同的名称,问题和解决方案会更容易理解。
  • @Clemens 它不能有不同的名称,因为这是它需要绑定的绑定名称,所以模型需要相同的名称。
  • @Clemens 我不想做 TxT="{Binding UCData.TxT}" 好像我会有更多属性我想通过 DataContext 将它们绑定到单个模型对象,而不是重复该代码对于每个属性,除了它应该与 DataContext 一起使用之外,每个人都说它很简单,但没有人有一个可行的解决方案,即使是在其他类似的问题上也是如此。在示例项目中,绑定通过 DataContext 工作,直接 TxY xaml 值不起作用。我两个都想要。
猜你喜欢
  • 1970-01-01
  • 2013-01-20
  • 1970-01-01
  • 2012-12-09
  • 2012-06-06
  • 2014-05-03
  • 1970-01-01
  • 2017-01-28
  • 2013-06-03
相关资源
最近更新 更多