gpt4 book ai didi

c# - 在自定义控件上绑定(bind) StringFormat

转载 作者:太空狗 更新时间:2023-10-29 22:53:53 25 4
gpt4 key购买 nike

我正在尝试在 WPF 应用程序中使用自定义控件,但在使用 StringFormat 绑定(bind)时遇到了一些问题。

问题很容易重现。首先,让我们创建一个 WPF 应用程序并将其命名为“TemplateBindingTest”。在那里,添加一个只有一个属性(文本)的自定义 ViewModel,并将其分配给窗口的 DataContext。将 Text 属性设置为“Hello World!”。

现在,向解决方案添加自定义控件。自定义控件尽可能简单:

using System.Windows;
using System.Windows.Controls;

namespace TemplateBindingTest
{
public class CustomControl : Control
{
static CustomControl()
{
TextProperty = DependencyProperty.Register(
"Text",
typeof(object),
typeof(CustomControl),
new FrameworkPropertyMetadata(null));

DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}

public static DependencyProperty TextProperty;

public object Text
{
get
{
return this.GetValue(TextProperty);
}

set
{
SetValue(TextProperty, value);
}
}
}
}

将自定义控件添加到解决方案时,Visual Studio 会自动创建一个 Themes 文件夹,其中包含一个 generic.xaml 文件。让我们将控件的默认样式放在那里:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TemplateBindingTest">

<Style TargetType="{x:Type local:CustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

现在,只需将控件添加到窗口,并使用 StringFormat 在 Text 属性上设置绑定(bind)。还要添加一个简单的 TextBlock 以确保绑定(bind)语法正确:

<Window x:Class="TemplateBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:TemplateBindingTest="clr-namespace:TemplateBindingTest" Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TemplateBindingTest:CustomControl Text="{Binding Path=Text, StringFormat=Test1: {0}}"/>
<TextBlock Text="{Binding Path=Text, StringFormat=Test2: {0}}" />
</StackPanel>

编译,运行,aaaaand...窗口显示的文字是:

Hello World!

Test2: Hello World!

在自定义控件上,StringFormat 被完全忽略。 VS 输出窗口上看不到任何错误。怎么回事?

编辑:解决方法。

好的,TemplateBinding 具有误导性。我找到了原因和肮脏的解决方法。

首先,请注意问题与 Button 的 Content 属性相同:

<Button Content="{Binding Path=Text, StringFormat=Test3: {0}}" />

所以,这是怎么回事?让我们使用 Reflector 并深入了解 BindingBase 类的 StringFormat 属性。 “Analyse”功能显示该属性由内部 DetermineEffectiveStringFormat 方法使用。让我们看看这个方法:

internal void DetermineEffectiveStringFormat()
{
Type propertyType = this.TargetProperty.PropertyType;
if (propertyType == typeof(string))
{
// Do some checks then assign the _effectiveStringFormat field
}
}

问题就在这里。 effectiveStringFormat 字段是解析绑定(bind)时使用的字段。并且仅当 DependencyProperty 的类型为 String 时才分配此字段(我的是,作为 Button 的 Content 属性,Object)。

为什么反对?因为我的自定义控件比我粘贴的要复杂一些,而且像 Button 一样,我希望控件的用户能够提供子控件而不仅仅是文本。

那么,现在呢?我们遇到了一种甚至存在于 WPF 核心控件中的行为,因此我可以“按原样”保留它。尽管如此,由于我的自定义控件仅用于内部项目,而且我希望它更容易从 XAML 中使用,所以我决定使用这个 hack:

using System.Windows;
using System.Windows.Controls;

namespace TemplateBindingTest
{
public class CustomControl : Control
{
static CustomControl()
{
TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(CustomControl),
new FrameworkPropertyMetadata(null, Callback));

HeaderProperty = DependencyProperty.Register(
"Header",
typeof(object),
typeof(CustomControl),
new FrameworkPropertyMetadata(null));

DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}

static void Callback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
obj.SetValue(HeaderProperty, e.NewValue);
}

public static DependencyProperty TextProperty;
public static DependencyProperty HeaderProperty;

public object Header
{
get
{
return this.GetValue(HeaderProperty);
}

set
{
SetValue(HeaderProperty, value);
}
}

public string Text
{
set
{
SetValue(TextProperty, value);
}
}
}
}

Header 是我的 TemplateBinding 中使用的属性。当向 Text 提供值时,将应用 StringFormat,因为该属性的类型为 String,然后将该值转发给 Header 属性使用回调。它有效,但它真的很脏:

  • HeaderText 属性不同步,因为当我更新 Header< 时 Text 没有更新。我选择不为 Text 属性提供 getter 以避免一些错误,但如果有人直接从 DependencyProperty (GetValue(TextProperty)) 读取值,它仍然会发生。
  • 如果有人为 HeaderText 属性提供值,则可能会发生不可预测的行为,因为其中一个值将丢失。

总的来说,我不会推荐使用这个 hack。仅当您真正可以控制您的项目时才这样做。如果该控件有哪怕一丁点机会用于另一个项目,请放弃 StringFormat。

最佳答案

使用 TemplateBinding 时不能传递 StringFormat 或 Converter。这里有一些解决方法。

关于c# - 在自定义控件上绑定(bind) StringFormat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8644942/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com