【发布时间】:2021-03-06 08:19:42
【问题描述】:
我在 WPF 中制作了一个自定义控件,它是星级。当有 5 颗星时,这些应该是金色的。
<UserControl x:Class="Lama.Wpf.Controls.RatingControl"
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:controls="clr-namespace:Lama.Wpf.Controls"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="RatingTemplate" TargetType="{x:Type ToggleButton}">
<Viewbox>
<Path Name="star" Fill="White" Opacity="0.2"
Data="F1 M 145.637,174.227L 127.619,110.39L 180.809,70.7577L 114.528,68.1664L 93.2725,5.33333L 70.3262,67.569L 4,68.3681L 56.0988,109.423L 36.3629,172.75L 91.508,135.888L 145.637,174.227 Z" />
</Viewbox>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Property="IsChecked" Value="True" />
<Condition
Binding="{Binding Rating, RelativeSource={RelativeSource FindAncestor, AncestorType=controls:RatingControl}}"
Value="5" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="star" Property="Fill" Value="Gold" />
<Setter TargetName="star" Property="Opacity" Value="1" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton Grid.Column="0" Tag="1" Padding="2" Template="{StaticResource RatingTemplate}"
Click="ClickEventHandler" />
<ToggleButton Grid.Column="1" Tag="2" Padding="2" Template="{StaticResource RatingTemplate}"
Click="ClickEventHandler" />
<ToggleButton Grid.Column="2" Tag="3" Padding="2" Template="{StaticResource RatingTemplate}"
Click="ClickEventHandler" />
<ToggleButton Grid.Column="3" Tag="4" Padding="2" Template="{StaticResource RatingTemplate}"
Click="ClickEventHandler" />
<ToggleButton Grid.Column="4" Tag="5" Padding="2" Template="{StaticResource RatingTemplate}"
Click="ClickEventHandler" />
</Grid>
</UserControl>
public partial class RatingControl
{
private const int Max = 5;
public static readonly DependencyProperty RatingProperty = DependencyProperty.Register(nameof(Rating),
typeof(int),
typeof(RatingControl),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
RatingChanged));
public int Rating
{
get => (int)GetValue(RatingProperty);
set
{
if (value < 0)
{
SetValue(RatingProperty, 0);
}
else if (value > Max)
{
SetValue(RatingProperty, Max);
}
else
{
SetValue(RatingProperty, value);
}
}
}
public RatingControl()
{
InitializeComponent();
}
private static void RatingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var item = sender as RatingControl;
var newVal = (int)e.NewValue;
var children = ((Grid)(item.Content)).Children;
ToggleButton button;
for (var i = 0; i < newVal; i++)
{
button = children[i] as ToggleButton;
if (button != null)
button.IsChecked = true;
}
for (var i = newVal; i < children.Count; i++)
{
button = children[i] as ToggleButton;
if (button != null)
button.IsChecked = false;
}
}
private void ClickEventHandler(object sender, RoutedEventArgs args)
{
var button = sender as ToggleButton;
if (button == null)
{
return;
}
var newValue = int.Parse(button.Tag.ToString());
Rating = newValue;
}
}
如果我运行它,我会得到这个异常:
InvalidOperationException: 'Binding' 必须具有非空值。
我是否在我的条件中绑定了错误的东西?因为如果我删除Rating-Binding,它可以工作,但我在这里看不到我的错误。
【问题讨论】:
-
请注意,在 XAML 中设置属性时不会调用 Rating 属性设置器,例如通过像
<local:RatingControl Rating="{Binding SomeProperty}"/>这样的绑定。 WPF 绕过 setter,直接调用SetValue。因此,除了SetValue(RatingProperty, value);之外,您在 setter 中不得有任何其他内容 -
是的,你是对的,我应该把这段代码写在dependencyproperty里面
-
不,来自属性设置器的代码应该在强制回调中。在这里,您可以在当前值最终传递给属性之前对其进行修改。