我有一个关于如何优雅地覆盖控件的可视树内的任意元素的问题.我也试图用几种不同的方式解决它,但我遇到了几个问题.通常当我尝试三条不同的路径并且每一路都失败时,我会下楼去喝咖啡,并问一个比我更聪明的人.所以我在这里.
具体细节:
我想要展平组合框的风格,这样它就不会引起人们的注意.我希望它类似于Windows.Forms.ComboBox的FlatStyle我希望它在Windows 7和XP上看起来一样.
主要是,我想改变ComboBox的ToggleButton的外观.
我可以使用Blend并撕掉控件模板的内部并手动更改它们.这对我来说听起来不是很开心.
我尝试使用样式来覆盖ToggleButton的背景,但事实证明整个ComboBox控件实际上是ToggleButton的前端.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ComboBoxExpiriment2.MainWindow"
x:Name="Window"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="204" Height="103">
<Grid x:Name="LayoutRoot">
<ComboBox HorizontalAlignment="Left" Margin="32,26.723,0,0" Width="120" VerticalAlignment="Top" Height="21.277">
<ComboBox.Style>
<Style>
<Setter Property="ToggleButton.Background" Value="Green" />
</Style>
</ComboBox.Style>
</ComboBox>
</Grid>
Run Code Online (Sandbox Code Playgroud)
所以我放弃并使用Blend将其撕掉.我发现它实际上是一个名为ComboBoxTransparentButtonStyle的Style,目标类型为ToggleButton.该样式设置一个ControlTemplate,它使用一个DockPanel,其右侧设置了"Microsoft_Windows_Themes:ClassicBorderDecorator"类型,这就是我们实际想要控制的内容.(到目前为止你和我在一起吗?)
这是照片:

<Style x:Key="ComboBoxTransparentButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="MinWidth" Value="0"/>
<Setter Property="MinHeight" Value="0"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="Auto"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{x:Static Microsoft_Windows_Themes:ClassicBorderDecorator.ClassicBorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<DockPanel SnapsToDevicePixels="true" Background="{TemplateBinding Background}" LastChildFill="false">
<Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Border" Width="{DynamicResource …Run Code Online (Sandbox Code Playgroud) 我厌倦了一遍又一遍地创建相同的图像+文本按钮,我想将标记移动到控件模板.这是我的问题:我需要提供模板绑定来将图像和文本添加到模板化按钮,而Button控件似乎没有我可以绑定的属性.
到目前为止,我的模板看起来像这样(对于未知的模板绑定,使用'???'):
<ControlTemplate x:Key="ImageButtonTemplate" TargetType="{x:Type Button}">
<StackPanel Height="Auto" Orientation="Horizontal">
<Image Source="{TemplateBinding ???}" Width="24" Height="24" Stretch="Fill"/>
<TextBlock Text="{TemplateBinding ???}" HorizontalAlignment="Left" Foreground="{DynamicResource TaskButtonTextBrush}" FontWeight="Bold" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="12" />
</StackPanel>
</ControlTemplate>
Run Code Online (Sandbox Code Playgroud)
是否可以使用控件模板创建此图像+文本按钮,或者我是否必须转到用户控件才能执行此操作?如果可以使用控件模板完成,我该如何设置模板绑定?
我知道这是一个很受欢迎的问题,但我找不到任何可以回答的问题,但如果我在搜索中遗漏了一些内容,我会道歉.
我正在尝试使用以下代码在运行时创建并测量控件(然后测量将用于选框样式滚动控件 - 每个控件的大小不同):
Label lb = new Label();
lb.DataContext= task;
Style style = (Style)FindResource("taskStyle");
lb.Style = style;
cnvMain.Children.Insert(0,lb);
width = lb.RenderSize.Width;
width = lb.ActualWidth;
width = lb.Width;
Run Code Online (Sandbox Code Playgroud)
代码创建一个Label控件并为其应用样式.该样式包含我的控件模板,该模板绑定到对象"任务".当我创建项目时它看起来很完美,但是当我尝试使用上面的任何属性测量控件时,我得到以下结果(我逐步检查并依次检查每个属性):
lb.Width = NaN
lb.RenderSize.Width = 0
lb.ActualWidth = 0
Run Code Online (Sandbox Code Playgroud)
有没有办法获得您在运行时创建的控件的渲染高度和宽度?
更新:
很抱歉取消选择您的解决方案作为答案.他们在我设置的基本示例系统上工作,但似乎没有完整的解决方案.
我觉得它可能与风格有关,所以很抱歉这个烂摊子,但我在这里粘贴整个东西.
一,资源:
<Storyboard x:Key="mouseOverGlowLeave">
<DoubleAnimation From="8" To="0" Duration="0:0:1" BeginTime="0:0:2" Storyboard.TargetProperty="GlowSize" Storyboard.TargetName="Glow"/>
</Storyboard>
<Storyboard x:Key="mouseOverTextLeave">
<ColorAnimation From="{StaticResource buttonLitColour}" To="Gray" Duration="0:0:3" Storyboard.TargetProperty="Color" Storyboard.TargetName="ForeColour"/>
</Storyboard>
<Color x:Key="buttonLitColour" R="30" G="144" B="255" A="255" />
<Storyboard x:Key="mouseOverText">
<ColorAnimation From="Gray" To="{StaticResource buttonLitColour}" Duration="0:0:1" Storyboard.TargetProperty="Color" Storyboard.TargetName="ForeColour"/>
</Storyboard> …Run Code Online (Sandbox Code Playgroud) 我有一个绑定到ObservableCollection的ListView.数据从Internet加载,然后添加到集合中.下载需要几秒钟,我想指示用户数据正在加载.
我创建了一个指示活动的UserControl.我将它放在ControlTemplate中.
<ControlTemplate x:Key="ListViewControlTemplate1" TargetType="{x:Type ListView}">
<Grid>
<local:ActivityIndicatorControl
HorizontalAlignment="Center"
Height="Auto"
Margin="0"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
Run Code Online (Sandbox Code Playgroud)
我想将Visibility绑定ActivityIndicatorControl到一个属性,让我们说bool IsLoading并相应地将它设置为Visible/Collapsed.
谢谢!
基本上,我不明白这里的真正区别是什么:
TabItem的Microsoft代码使用:
<ContentPresenter ContentSource="Header" ... />
Run Code Online (Sandbox Code Playgroud)
那么,何时使用该Content属性而不是(或除此之外)ContentSource?
考虑第一版代码(MainWindow.xaml):
<ScrollViewer>
<local:CustomControl1 Width="1000" Height="1000" Background="Red"/>
</ScrollViewer>
Run Code Online (Sandbox Code Playgroud)
其中CustomControl1派生自ItemsControl.在CustomControl1中,我重写了OnMouseDown事件.这段代码完美无缺,我确实抓住了鼠标按下事件.
现在第二版代码(MainWindow.xaml):
<local:CustomControl1 Width="1000" Height="1000" Background="Red"/>
Run Code Online (Sandbox Code Playgroud)
在Generic.xaml里面,我更改了我的项目控件的模板:
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible"
>
<ItemsPresenter/>
</ScrollViewer>
</Border>
</ControlTemplate>
Run Code Online (Sandbox Code Playgroud)
当我将scrollviewer作为控件模板的一部分时,我不再接收OnMouseDownEvent(左键单击).出于某种原因,现在将鼠标按下事件标记为已处理.如果不是重写OnMouseDown,我在items控件构造函数中使用以下语句,则捕获事件:
AddHandler(Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseDown), true);
Run Code Online (Sandbox Code Playgroud)
首先,我想了解为什么将scrollviewer放在模板中改变鼠标的行为.第二,有没有人知道一些解决方法?我提出的解决方案(通过捕获处理事件)对我来说是不可接受的.在我的应用程序中,只有当没有任何项控制子项处理它时,我才需要处理鼠标按下事件.
提前致谢.
我对那些肯定是最常见的WPF要求之一感到困惑.我已经阅读了这个问题但是我的解决方案的实现不起作用.
这是无视控件的标记:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfTest">
<Style TargetType="{x:Type local:CustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<Border>
<TextBox x:Name="myTextBox" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused"
Value="True">
<Setter Property="FocusManager.FocusedElement"
Value="{Binding ElementName=myTextBox}" />
<Setter TargetName="myTextBox"
Property="Background"
Value="Green" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)
这是包含CustomControl实例的Window的标记:
<Window x:Class="WpfTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfTest"
Title="Window1" Height="300" Width="300">
<local:CustomControl x:Name="CCtl" />
</Window>
Run Code Online (Sandbox Code Playgroud)
这是代码隐藏的代码:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Loaded += (RoutedEventHandler)delegate { CCtl.Focus(); };
}
}
Run Code Online (Sandbox Code Playgroud)
加载Window1时,文本框变为绿色(表示触发器有效)但焦点仍然是CCtl而不是文本框.毫无疑问,这与显示以下数据错误的输出有关:
无法找到引用'ElementName = myTextBox'的绑定源.BindingExpression …
我正在尝试为Expander控件创建自己的模板.当控件展开时,我希望内容缓慢滑下.
在编译时不知道内容的期望高度.
我以为我们可以将幻灯片定义为动画:
<Storyboard x:Key="ExpandContent">
<DoubleAnimation
Storyboard.TargetName="_expanderContent"
Storyboard.TargetProperty="Height"
From="0.0"
To="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
Duration="0:0:1.0" />
</Storyboard>
Run Code Online (Sandbox Code Playgroud)
但不幸的是没有.我们收到错误
无法冻结此Storyboard时间轴树以跨线程使用.
看来我们在定义动画参数时不能使用绑定.(也在这个问题中讨论过.)
有没有人对我如何处理这个有任何想法?我担心使用LayoutTransform.ScaleY,因为这会产生扭曲的图像.
这与此问题类似,但这个问题的答案涉及编写代码隐藏,我认为在控件模板中是不可能的.我想知道基于XAML的解决方案是否可以实现.
<ControlTemplate x:Key="ExpanderControlTemplate" TargetType="{x:Type Expander}">
<ControlTemplate.Resources>
<!-- Here are the storyboards which don't work -->
<Storyboard x:Key="ExpandContent">
<DoubleAnimation
Storyboard.TargetName="_expanderContent"
Storyboard.TargetProperty="Height"
From="0.0"
To="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
Duration="0:0:1.0" />
</Storyboard>
<Storyboard x:Key="ContractContent">
<DoubleAnimation
Storyboard.TargetName="_expanderContent"
Storyboard.TargetProperty="Height"
From="{Binding ElementName=_expanderContent,Path=DesiredHeight}"
To="0.0"
Duration="0:0:1.0" />
</Storyboard>
</ControlTemplate.Resources>
<Grid Name="MainGrid" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Name="ContentRow" Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" …Run Code Online (Sandbox Code Playgroud) 我正在对ExpBox中的TextBox的DataSource进行一些验证,并且发现一旦触发了验证错误,如果我折叠了Expander,红色框就会停留在TextBox所在的位置.
<Expander Header="Blah Blah Blah">
<TextBox Name="TextBox"
Validation.ErrorTemplate="{DynamicResource TextBoxErrorTemplate}"
Text="{Binding Path=Blah,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}" />
</Expander>
Run Code Online (Sandbox Code Playgroud)
我试图通过将错误模板的可见性绑定到扩展器来解决这个问题,但是我认为绑定有问题.
<local:NotVisibleConverter x:Key="NotVisibleConverter" />
<ControlTemplate x:Key="TextBoxErrorTemplate">
<DockPanel>
<Border BorderBrush="Red" BorderThickness="2"
Visibility="{Binding Path=IsExpanded,
Converter={StaticResource NotVisibleConverter},
RelativeSource={RelativeSource AncestorType=Expander}}" >
<AdornedElementPlaceholder Name="MyAdorner" />
</Border>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Run Code Online (Sandbox Code Playgroud)
我想我的绑定出了问题,有人可以让我回到正轨吗?或者,是否有人知道ErrorTemplate的另一个解决方案仍然可以在Expander崩溃时看到?
我有多个TextBlocks,它引用了我的应用程序中的不同元素.我的代码在页面中直接使用时工作正常.但是,我想创建一个ControlTemplate和一个ContentControl来减少代码的重复.
如何使用TemplateBinding从ContentControl传递对ElementName的引用到ControlTemplate?以下代码抛出此错误:
"无法将属性'ElementName'中的值转换为'System.String'类型的对象.'System.Windows.TemplateBindingExpression'类型的对象无法转换为'System.String'类型."
除了Tag属性之外,我还尝试了ContentStringFormat,它也没有用.
使用模板使其工作的正确方法是什么?
在此先感谢您的帮助,
---肖恩
这是代码示例:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Page.Resources>
<ControlTemplate x:Key="MyTemplate" TargetType="{x:Type ContentControl}">
<TextBlock Margin="{Binding ElementName={TemplateBinding Tag}, Path=Margin}" Text="{TemplateBinding Content}" TextAlignment="{Binding ElementName={TemplateBinding Tag}, Path=TextAlignment}" Width="{Binding ElementName={TemplateBinding Tag}, Path=Width}" />
</ControlTemplate>
</Page.Resources>
<StackPanel>
<TextBlock x:Name="AnotherElement" Margin="10" Text="Main TextBlock" TextAlignment="Center" Width="100" />
<TextBlock x:Name="AnotherElement2" Margin="20" Text="Second TextBlock" TextAlignment="Left" Width="250" />
<TextBlock Margin="{Binding ElementName=AnotherElement, Path=Margin}" Text="Here is my TextBlock!" TextAlignment="{Binding ElementName=AnotherElement, Path=TextAlignment}" TextTrimming="CharacterEllipsis" Width="{Binding ElementName=AnotherElement, Path=Width}" />
<TextBlock Margin="{Binding ElementName=AnotherElement2, Path=Margin}" Text="Here is my Second TextBlock!" TextAlignment="{Binding ElementName=AnotherElement2, …Run Code Online (Sandbox Code Playgroud) controltemplate ×10
wpf ×10
xaml ×4
binding ×3
c# ×2
styles ×2
animation ×1
combobox ×1
data-binding ×1
focus ×1
focusmanager ×1
scrollviewer ×1
templates ×1
validation ×1