TemplateBinding在WPF自定义控件中的INotifyPropertyChanged上不起作用



我最近在WPF中创建了一个IconButton作为CustomControl。它正在为DependencyProperties使用TemplateBinding:

IconButton.cs

public class IconButton : Button
{
public static readonly DependencyProperty TextProperty;
public static readonly DependencyProperty MDL2IconCodeProperty;
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}

public string MDL2IconCode
{
get { return (string)GetValue(MDL2IconCodeProperty); }
set { SetValue(MDL2IconCodeProperty, value); }
}

static IconButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(IconButton),
new FrameworkPropertyMetadata(typeof(IconButton)));
TextProperty = DependencyProperty.Register("Text",
typeof(string),
typeof(IconButton),
new PropertyMetadata("Button text", OnTextChanged));
MDL2IconCodeProperty = DependencyProperty.Register("MDL2IconCode",
typeof(string),
typeof(IconButton),
new PropertyMetadata("uf13e", OnIconTextChanged));
}
static void OnTextChanged(DependencyObject o,
DependencyPropertyChangedEventArgs e)
{
var iconButton = o as IconButton;
if (iconButton == null)
{
return;
}
string newText = e.NewValue as string;
iconButton.Text = newText;
}
static void OnIconTextChanged(DependencyObject o,
DependencyPropertyChangedEventArgs e)
{
var iconButton = o as IconButton;
if (iconButton == null)
{
return;
}
string newText = e.NewValue as string;
iconButton.MDL2IconCode = newText;
}
}

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:UI.CustomControls">

<Style TargetType="{x:Type local:IconButton}" 
BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:IconButton}">
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
Command="{TemplateBinding Command}"
CommandParameter="{TemplateBinding CommandParameter}"
CommandTarget="{TemplateBinding CommandTarget}">
<StackPanel>
<TextBlock HorizontalAlignment="Center"
Text="{TemplateBinding MDL2IconCode}"
FontFamily="Segoe MDL2 Assets"
FontSize="16"
x:Name="iconTextBlock"/>
<TextBlock HorizontalAlignment="Center" 
Text="{TemplateBinding Text}"
x:Name="textTextBlock"/>
</StackPanel>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

但是它只起一半的作用。我很快意识到,绑定到DependencyProperties只能在XAML设计器中工作,而不能在ViewModel中工作。当我在设计器中设置Text属性时,它能工作。但是从ViewModel绑定到它,属性既不是初始设置,也不是在INotifyPropertyChanged事件中更新。

作为测试,我将TemplateBinding of Text属性更改为
{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text}

但它没有帮助。

我的代码可能有什么问题?

是INotifyPropertyChanged支持WPF自定义控件与TemplateBinding在所有?

问题是您以破坏Binding的方式设置TextMDL2IconCode的新值,因此更改不会传播到UI。

iconButton.Text = newText;
....
iconButton.MDL2IconCode = newText;

正确的方法是使用SetCurrentValue方法来改变属性的有效值,但是现有的触发器、数据绑定和样式将继续工作。

static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var iconButton = o as IconButton;
if (iconButton == null)
{
return;
}
string newText = e.NewValue as string;
iconButton.SetCurrentValue(TextProperty, newText);
}
static void OnIconTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var iconButton = o as IconButton;
if (iconButton == null)
{
return;
}
string newText = e.NewValue as string;
iconButton.SetCurrentValue(MDL2IconCodeProperty, newText);
}

但是如果你在OnTextChangedOnIconTextChanged中没有任何特殊的逻辑,那么你可以去掉PropertyChangedCallbacks,它仍然可以工作。

TextProperty = DependencyProperty.Register("Text",
typeof(string),
typeof(IconButton),
new PropertyMetadata("Button text"));
MDL2IconCodeProperty = DependencyProperty.Register("MDL2IconCode",
typeof(string),
typeof(IconButton),
new PropertyMetadata("uf13e"));

相关内容

  • 没有找到相关文章

最新更新