WPF:如何在你自己的c#代码中使XAML中的样式以变量为条件

本文关键字:XAML 样式 条件 变量 代码 你自己 自己的 WPF | 更新日期: 2023-09-27 18:04:44

这里是WPF和XAML新手....

我需要将XAML代码中的WPF TriggerDataTrigger绑定到XAML控件类以外的类中的一些c#代码中。这是非常令人沮丧的,因为我读过的所有28,000个教程只给出了TriggerDataTrigger的一个微不足道的例子,这些例子涉及已经存在的属性(例如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文件中,我玩了TriggerDataTrigger的各种咒语,不知道如何使它工作。在任何情况下,诊断报告都具有与其他报告相同的默认特征。

<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>

如何让TriggerReportSettingsData.SelectedReport == SelectedReportType.DiagSummary时开火?

WPF:如何在你自己的c#代码中使XAML中的样式以变量为条件

如何使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;
        }
    }

根据评论,选择的多样性使模板建议增加到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}"