我尝试创建一个名为MyComboBox
的自定义ComboBox。它有一个按钮,用于在上一个和下一个项目之间切换。
我将基础的背景颜色存储在BaseBackground
中。这很有用,因为我不希望FrontGlyph
从模板化父级继承Background
。
这是我的WPF代码:
<Style x:Key="{x:Type local:MyComboBox}" TargetType="{x:Type local:MyComboBox}">
</Style.Resources>
<Setter Property="Focusable" Value="False" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyComboBox}">
<Grid Cursor="Hand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!-- A glyph will come here -->
<ColumnDefinition Width="*" /> <!-- The base combo box can take as much space as it can. -->
</Grid.ColumnDefinitions>
<Path x:Name="FrontGlyph" Grid.Column="0" Data="M 0.0 16.0 L 6.0 0.0 L 6.0 16.0 Z" Fill="{TemplateBinding BaseBackground}" Stretch="Fill" />
<Grid x:Name="BaseComboBox" Grid.Column="1" Background="{TemplateBinding BaseBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!-- Previous item -->
<ColumnDefinition Width="Auto" /> <!-- Next item -->
<ColumnDefinition Width="*" /> <!-- Content Presenter -->
<ColumnDefinition Width="Auto" /> <!-- Drop down button -->
</Grid.ColumnDefinitions>
<Button x:Name="Prev" Grid.Column="0" Background="{TemplateBinding Background}" Style="{StaticResource MyUIButton}">
<Path VerticalAlignment="Center" Data="M 4.5 0.5 L 0.5 4.5 L 4.5 8.5 Z" Fill="Black" />
</Button>
<Button x:Name="Next" Grid.Column="1" Background="{TemplateBinding Background}" Style="{StaticResource MyUIButton}">
<Path VerticalAlignment="Center" Data="M 0.5 0.5 L 4.5 4.5 L 0.5 8.5 Z" Fill="Black" />
</Button>
<ContentPresenter x:Name="ContentSite" Grid.Column="2" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" VerticalAlignment="Stretch" HorizontalAlignment="Left" />
<ToggleButton x:Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="3" Focusable="false" ClickMode="Press" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Background="{TemplateBinding Background}" />
<Popup x:Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid x:Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" BorderThickness="1" BorderBrush="{TemplateBinding Background, Converter={StaticResource LightenBrushColor}, ConverterParameter=0.5}" Background="{TemplateBinding Background}" />
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BaseBackground" Value="Goldenrod" /> <!-- This does not work -->
<!--<Setter TargetName="FrontGlyph" Property="Fill" Value="Goldenrod" />
<Setter TargetName="BaseComboBox" Property="Background" Value="{Binding Path=Fill, ElementName=FrontGlyph}" />--> <!-- These 2 lines do work. -->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这是MyComboBox
的源代码:
class MyComboBox : ComboBox
{
public static readonly DependencyProperty BaseBackgroundProperty;
public SolidColorBrush BaseBackground { get { return (SolidColorBrush)GetValue(BaseBackgroundProperty); } set { SetValue(BaseBackgroundProperty, value); } }
static MyComboBox()
{
BaseBackgroundProperty = DependencyProperty.Register("BaseBackground", typeof(SolidColorBrush), typeof(MyComboBox), new FrameworkPropertyMetadata(Brushes.Lime, FrameworkPropertyMetadataOptions.AffectsRender, OnBaseBackgroundPropertyChanged));
}
public MyComboBox()
{
DefaultStyleKey = typeof(MyComboBox);
}
private static void OnBaseBackgroundPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
// This is not called when the trigger tries to set BaseBackground when the mouse is over the control
}
}
当我将鼠标悬停在控件上时,它应该更改颜色。我应该可以通过更改BaseBackground
来执行此操作,因为FrontGlyph
和BaseComboBox
的背景颜色都与此绑定。然而,代码编译但不会发生变化。不只是在UI上,但如果我调试代码,我也看不到C#的变化。
如果我更改FrontGlyph
的背景颜色并将BaseComboBox.BackgroundColor
绑定到该颜色,则效果很好。
有人可以解释为什么我的自定义属性BaseBackground
的更改未注册?它不能是标准的“实现INotifyPropertyChanged
接口”。问题,因为我使用Brush
作为我的财产,而刷子在其他地方工作得很好。 :)
我的实施可能看起来很傻。好吧,我是WPF的新手。另外,我不想让你担心整个实现,只是试图复制关键部分。
我发现在我的源代码中,如果满足某些条件,我会设置BaseBackground = new SolidColorBrush(...)
。如果我删除这行代码,现在触发器工作,BaseBackground被赋予Goldenrod颜色。
但我想知道,为什么从C#代码更改DependencyProperty会阻止它从XAML标记中运行。此外,我需要他们两个工作。
谢谢。
答案 0 :(得分:1)
<强>摘要强>
我认为您可能要做的是在名称BaseBackgroundProperty
(而非"BaseBackground"
)下注册"Background"
,因为您的xaml正在尝试使用该名称设置属性。< / p>
<强>详情
查看代码,我认为永远不会设置MyComboBox.BaseBackground
属性的原因是因为它是使用名称"Background"
向依赖属性系统注册的。这意味着您在基类中注册了"Background"
(Control.BackgroundProperty
)的属性,以及在派生类中注册为"Background"
(MyComboBox.BaseBackgroundProperty
)的属性。因此,理论上,在xaml中设置"Background"
最终应设置为MyComboBox.BaseBackgroundProperty
,而设置"Control.Background"
时最终应设置Control.Background
属性。
虽然这在理论上有效,但我不知道它是否在实践中有效。这也不是真正做事的方式。如果你想以某种方式修改你班级的现有属性,你可以在你的类型初始化器(也就是静态构造函数)中覆盖Control.BackgroundProperty
的元数据,但我不认为这就是你的意图在这里。您的xaml正在尝试设置名为"BaseBackground"
的不存在的属性。
答案 1 :(得分:1)
根据您的问题更新,您正在做的是在依赖项属性上设置本地值,这可能会破坏模板绑定。在通过某些其他方式设置目标的某些情况下,这可能发生单向绑定。在这种情况下,您似乎正在设置源,但可能会导致绑定中断。
您可以通过将绑定的PresentationTraceSources.TraceLevel属性设置为&#34;高&#34;来调试绑定。 (您可能需要使用标准{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}
语法而不是{TemplateBinding}
快捷语法才能附加属性 - 我不确定。)然后,运行应用程序并查看调试输出。它会告诉你绑定是否被破坏。
如果绑定实际上已被破坏,您可以采取不同的措施来修复它,具体取决于您的使用情况。
TwoWay
,以防止其破坏。SetValue
从代码设置它,因为许多控件在从代码修改自己的依赖项属性时往往会这样做。潜在相关信息: