【问题标题】:How to bind to the control property itself, instead of DataContext value property?如何绑定到控件属性本身,而不是 DataContext 值属性?
【发布时间】:2019-07-08 10:54:11
【问题描述】:

我有一个用户控件。使用 XAML。它有自己的属性,它的 ViewModel 对象设置为 DataContext:

<ComboBox ItemsSource="{Binding Items}" SelectedIndex="0">
  <ComboBox.DataContext>
    <vm:WindowsProfilePicker />
  </ComboBox.DataContext>

绑定到它的 DataContext 值属性非常简单,并且可以按预期工作。

假设:

<Image Source="{Binding UserImage}" />

UserImageViewModel 的属性。

Image 元素是我的用户控件的一部分。该控件有自己的名为ImageSize 的属性,定义如下:

public static readonly DependencyProperty ImageSizeProperty
  = DependencyProperty.Register(
    "ImageSize",
    typeof(double),
    typeof(WindowsProfilePicker),
    new FrameworkPropertyMetadata(126.0)
);

当然,我们在代码中有 getter 和 setter:

public double ImageSize {
  get => (double)GetValue(ImageSizeProperty);
  set => SetValue(ImageSizeProperty, value);
}

现在我想在我的UserControl 的 XAML 中引用该属性。它看起来像这样:

<Image
  Width="
    {Binding RelativeSource={RelativeSource AncestorType=local:WindowsProfilePicker},
      Path=ImageSize}"
  Height="{Binding RelativeSource={RelativeSource AncestorType=local:WindowsProfilePicker},
      Path=ImageSize}"
  Source="{Binding UserImage}" />

好看吗?不是真的,它不起作用。我没有收到错误,没有警告,但未设置图像大小。控件中的图像根据源位图大小设置其大小。当我用数字替换绑定时,它可以工作,大小是固定的。但是,我希望将新控件的 ImageSize 属性用作 Image WidthHeight。我做错了什么?

顺便说一句,显然我不希望该属性与我的 ViewModel 绑定,因为它是严格的呈现功能,与数据无关。

必须在 XAML 中设置尺寸等视觉效果(最好是样式),在代码中设置数据(在我的情况下为用户个人资料图片),在控件的 ViewModel 中设置。

【问题讨论】:

  • UserControl 拥有自己的视图模型通常是错误的,即设置自己的 DataContext。相反,它将公开绑定到其继承的 DataContext 中的对象属性的依赖属性,即由其父元素提供的属性,例如一个窗口或页面。
  • 在 UserControl 的 XAML 中,您使用 RelativeSource 绑定,例如 &lt;Image Source="{Binding UserImage, RelativeSource={RelativeSource AncestorType=UserControl}}" /&gt;,其中 UserImage 是控件的依赖属性。
  • 您检查过Output 窗口吗?可能存在绑定或转换错误?
  • @Clemens:那么在代码隐藏而不是 ViewModel 中填充项目容器是一种好习惯吗?我的意思是“使用”控件的主模块将仅使用选择值(当前项)。该控件是一个用户配置文件选择器,因此它独立于应用程序,结果仅取决于用户的系统。
  • @IDarkCoder:我查过了。没有错误或其他指示无效绑定的消息。

标签: c# .net wpf xaml


【解决方案1】:

尝试像这样配置属性元数据:

    public static readonly DependencyProperty ImageSizeProperty
      = DependencyProperty.Register(
        "ImageSize",
        typeof(double),
        typeof(WindowsProfilePicker),
        new FrameworkPropertyMetadata((double)126.0, 
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
            | FrameworkPropertyMetadataOptions.AffectsRender
            | FrameworkPropertyMetadataOptions.AffectsMeasure)
    );

    [TypeConverter(typeof(LengthConverter))]
    public double ImageSize
    {
        get => (double)GetValue(ImageSizeProperty);
        set => SetValue(ImageSizeProperty, value);
    }

    public static readonly DependencyProperty ImageSizeProperty
      = DependencyProperty.Register(
        "ImageSize",
        typeof(double),
        typeof(WindowsProfilePicker),
        new FrameworkPropertyMetadata((double)126.0, 
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
            | FrameworkPropertyMetadataOptions.AffectsRender
            | FrameworkPropertyMetadataOptions.AffectsMeasure)
    {
         BindsTwoWayByDefault = true,
         DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
     });

AffectsRender & AffectsMeasure 可能不是必需的)

【讨论】:

  • 好吧,奇怪的是——即使在重建整个东西之后,设计器视图中也没有任何反应,但是它在运行时工作!我想像其他选项有助于传播大小值,我想知道为什么它在设计时不起作用。设计者设法从系统收集数据并构建所有图像,但未能将双精度值从一个 XAML 元素传递到另一个。
  • @Harry 我同意它不能在设计器中可靠地工作,这很烦人。虽然,如果您将 UserControl 添加到另一个控件或窗口然后重建,它应该可以工作。虽然这种行为有时是不可预测的(例如,有时我需要关闭 xaml 文件并再次打开它才能工作;如果您的 UC 在同一个项目中而不是在单独的项目中,它的行为也会有所不同)。跨度>
  • @Harry 您可能还想尝试其他 FrameworkPropertyMetadataOptions docs.microsoft.com/en-us/dotnet/api/… 也许诸如“AffectsParentMeasure”之类的东西可以解决问题?
  • 这是可能的,因为内部 Image 元素是调整外部元素大小的唯一参考点。
猜你喜欢
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 2013-07-25
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2014-03-24
相关资源
最近更新 更多