WPF:如何在你自己的c#代码中使XAML中的样式以变量为条件
本文关键字:XAML 样式 条件 变量 代码 你自己 自己的 WPF | 更新日期: 2023-09-27 18:04:44
这里是WPF和XAML新手....
我需要将XAML代码中的WPF Trigger
或DataTrigger
绑定到XAML控件类以外的类中的一些c#代码中。这是非常令人沮丧的,因为我读过的所有28,000个教程只给出了Trigger
或DataTrigger
的一个微不足道的例子,这些例子涉及已经存在的属性(例如MouseOver
),没有一个例子说明如何将其与自己的c#代码联系起来。
我有一个显示各种报告类型的屏幕。所有报告类型的XAML都是相同的,除了诊断报告,我的要求是DataGrid单元格配置为TextBlock.TextAlignment="Left"
,而所有其他报告(即默认)应该是TextBlock.TextAlignment="Center"
。(还有其他一些不同之处;为简洁起见,我就说这是唯一的区别。)我真的不想复制整个XAML来对诊断报告进行特殊处理,因为其中99%的内容将与其他报告相同。
要使用触发器,我想也许我需要我的类继承DependencyObject,这样我就可以在其中定义DependencyProperty(作为一个WPF新手,我意识到我可能会说一些非常奇怪的事情)。在我的c#代码中,我有一个类。
namespace MyApplication
{
public enum SelectedReportType
{
EquipSummary,
EventSummary,
UserSummary,
DiagSummary
}
public sealed class ReportSettingsData : DependencyObject
{
private static ReportSettingsData _instance; // singleton
static ReportSettingsData() { new ReportSettingsData(); }
private ReportSettingsData() // private because it's a singleton
{
if (_instance == null) // only true when called via the static constructor
_instance = this; // set here instead of the static constructor so it's available immediately
SelectedReport = SelectedReportType.EquipSummary; // set the initial/default report type
}
public static ReportSettingsData Instance
{
get { return _instance; }
}
public static SelectedReportType SelectedReport
{
get { return (SelectedReportType)Instance.GetValue(SelectedReportProperty); }
set { Instance.SetValue(SelectedReportProperty, value); }
}
public static readonly DependencyProperty SelectedReportProperty =
DependencyProperty.Register("SelectedReport", typeof(SelectedReportType), typeof(ReportSettingsData));
}
}
所以在我的XAML文件中,我玩了Trigger
和DataTrigger
的各种咒语,不知道如何使它工作。在任何情况下,诊断报告都具有与其他报告相同的默认特征。
<my:HeaderVisual x:Class="MyApplication.ReportsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:MyApplication">
<DataGrid Name="_dgReport"
ColumnWidth="Auto"
CanUserAddRows="False"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
ItemsSource="{Binding}"
IsReadOnly="True">
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<Setter Property="TextBlock.TextAlignment" Value="Center"></Setter>
<Style.Triggers>
<!-- Override some property settings for Diagnostics reports... -->
<!--
<DataTrigger Binding="{Binding my:ReportSettingsData.SelectedReport}" Value="DiagSummary">
<DataTrigger Binding="{Binding Path=my:ReportSettingsData.SelectedReport}" Value="DiagSummary">
-->
<Trigger Property="my:ReportSettingsData.SelectedReport" Value="DiagSummary">
<Setter Property="TextBlock.TextAlignment" Value="Left"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>
</my:HeaderVisual>
如何让Trigger
在ReportSettingsData.SelectedReport == SelectedReportType.DiagSummary
时开火?
如何使XAML中的样式以您自己的c#代码中的变量为条件
我建议你看看CellTemplate选择器(GridViewColumn)。CellTemplateSelector属性(System.Windows.Controls)),您可以在后面的代码中执行选择逻辑。
<粗糙的例子/strong>
只需定义资源
中所需的模板(4个,但有两个)<Window.Resources>
<DataTemplate x:Key="EquipTemplate">
<TextBlock Margin="2" Text="Equip" Foreground="Green"/>
</DataTemplate>
<DataTemplate x:Key="EventTemplate">
<TextBlock Margin="2" Text="Event" Foreground="Red"/>
</DataTemplate>
<DataTemplate x:Key="UserTemplate" ...
</Window.Resources>
Xaml模板使用选择器
<DataGridTemplateColumn Header="My Event">
<DataGridTemplateColumn.CellTemplateSelector>
<local:SelectedReportTypeTemplateSelector
EquipTemplate="{StaticResource EquipTemplate}"
EventTemplate="{StaticResource EventTemplate}"
User...
/>
</DataGridTemplateColumn.CellTemplateSelector>
</DataGridTemplateColumn>
代码后面
public class MeetingTemplateSelector : DataTemplateSelector
{
public DataTemplate EquipTemplate { get; set; }
public DataTemplate EventTemplate { get; set; }
public DataTemplate UserTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item,
DependencyObject container)
{
DataTemplate result;
switch( ((ReportSettingsData) item).SelectedReport)
{
case EquipSummary : result = EquipTemplate; break;
case EventSummary : result = EventTemplate; break;
case UserSummary ..
}
return result;
}
}
更新strong>
根据评论,选择的多样性使模板建议增加到30多个模板。另一种方法可能是用操作属性代替触发的操作来扩展目标类。例如,我们需要显示红色,在实例和bind中提供它。
public Partial MyClassInstance
{
public Brush ColorMeAs
{
get { return this.IsValid ? BrushGreen : BrushRed; }
}
... other properties as such:
}
则按此绑定
Foreground="{Binding ColorMeAs}"
触发
下面是一个从我的存档中提取的数据触发器的示例:
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Width" Value="80" />
<Setter Property="Height" Value="28"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=LoginInProcess}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=LoginInProcess}" Value="False">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
您的c#代码看起来很好,并且您已经有了引用MyApplication名称空间的XML名称空间声明,因此:
您应该能够使用x:Static
标记使用枚举标识符访问枚举值,如本示例所示(我喜欢这个示例,因为它还展示了如何使用非自定义x:Static以及如何进行一些树遍历):
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True" />
<Condition Binding="{Binding Type}" Value="{x:Static loc:AppProfileItemType.Custom}" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="PART_Delete" Property="Visibility" Value="{x:Static Visibility.Visible}" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</DataTemplate.Triggers>
在你的例子中,你的enum的标记应该是:
Value="{x:Static my:SelectedReportType.DiagSummary}"