【问题标题】:Creating 'dynamic' DataTemplates at runtime在运行时创建“动态”数据模板
【发布时间】:2018-03-22 08:55:56
【问题描述】:

我目前遇到这样一种情况,即在运行时创建 DataGrid 单元格的模板,因为属性名称是动态的并且在设计时是未知的。例如,此处使用“ColumnName”(来自 DataColumn)作为 Binding 的路径,以获取填充椭圆的颜色:

                       myCellTemplate = "<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> " &
                                       "<Ellipse Width=""25"" Height=""25"" Margin=""0,3"" Stroke=""Black"" StrokeThickness=""1"" " &
                                       "Fill=""{Binding [" & myColumn.ColumnName & "], Converter={StaticResource myConverter}}""></Ellipse></DataTemplate>"

有什么方法可以实现相同的效果,但将我的 DataTemplate 放在 ResourceDictionary 中,而不是放在后面的代码中?能够以通常的方式编辑模板会更可取。

谢谢。

【问题讨论】:

  • 您是否将动态值传递给转换器?如果是这样,您打算如何在转换器中使用它们?您知道可能使用的值吗?
  • 您可以将 XAML 中定义的模板视为纯字符串或 XML,并以一种或另一种方式执行替换。但是没有“特定于 WPF 的方式”可以简单地替换您以编程方式在 XAML 中定义的模板的一部分。

标签: wpf xaml


【解决方案1】:

XAML 是 XML,因此您可以这样操作它,或者您可以将它作为字符串加载并使用字符串操作。 一旦编译成 baml 就有点麻烦了。 但是可以从“平面”未编译文件中加载资源字典。 如果 localappdata 并对其进行操作,则可以拥有未编译的资源字典。 有许多示例可以执行此处链接的此类操作: https://social.technet.microsoft.com/wiki/contents/articles/28797.wpf-dynamic-xaml.aspx

或者您可以在 txt 文件中包含一段 xaml 并对其进行操作。 在我正在开发的套件中,我有一个这样的 txt 文件,其中包含:

    <?xml version="1.0" encoding="utf-8" ?>
<DataGridTextColumn Binding="{Binding Factor[^^^Index^^^], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"  
 xmlns:ui="clr-namespace:UILib;assembly=UILib"
 xmlns:local="clr-namespace:ScenarioEditor"
 xmlns:model="clr-namespace:ModelLib;assembly=ModelLib"
>

        <DataGridTextColumn.HeaderTemplate>
            <DataTemplate>
                <ui:IconParent Height="20" Width="30" 
                        ui:IconParent.IPType="{x:Static model:UnitTypes.^^^EnumString^^^}"
                        ui:Icon.UnitType="{x:Static model:UnitTypes.^^^EnumString^^^}"
                        ui:Icon.Side="{Binding DataContext.DefenderSide
                            , RelativeSource={RelativeSource AncestorType=UserControl}}"
                        >
                    <ui:IconParent.ToolTip>
                        <ToolTip>
                            ^^^EnumDescription^^^
                        </ToolTip>
                    </ui:IconParent.ToolTip>
                        <ui:UnitIcon Margin="2"/>
                </ui:IconParent>
            </DataTemplate>
        </DataGridTextColumn.HeaderTemplate>
    </DataGridTextColumn>

然后我使用以下代码构建数据网格:

XElement col = GetXElement(@"pack://application:,,,/Views/AttackFactors/attackFactorColumn.txt");
foreach (UnitTypes ut in  Enum.GetValues(typeof(UnitTypes)).Cast<UnitTypes>().Where(x=>x.ThisFights()==true).Select(x=>x).ToList())
{
    XElement el = new XElement(col);
    string colString = el.ToString()
        .Replace("^^^Index^^^", ((int)ut).ToString())
        .Replace("^^^EnumString^^^", ut.ToString())
        .Replace("^^^EnumDescription^^^", ut.ToDescriptionString());
    ParserContext context = new ParserContext();
    context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
    DataGridTextColumn tc = (DataGridTextColumn)XamlReader.Parse(colString, context);
    dg.Columns.Add(tc);
};

您可以扩展该原则以构建在设计时合并的资源字典,以便您可以看到对设计时数据的影响。

仅设计时资源字典: https://github.com/jbe2277/waf/wiki/WPF-Design-Time-Support-(Part-2)

【讨论】:

  • 虽然我希望有一种方法可以更直接地使用我的“动态”资源字典,但您的想法使我朝着正确的方向前进,因此不必在代码中编辑 XAML-在连接的字符串变量后面。非常感谢你。
【解决方案2】:

动态创建单元格模板的一种方法是为您的单元格模板设置ContentControl,并在Style.Triggers 中为您的ContentControl 设置多个检查属性(在您的情况下为“ColumnName”)的DataTrigger。

从那里您可以将ContentControltemplate 属性设置为您选择的任何ControlTemplate,并将它们存储在ResourceDictionary

XAML:

<DataTemplate>
    <ContentControl>
        <ContentControl.Style>
            <Style TargetType="ContentControl">
                <Style.Triggers>

                    <DataTrigger Binding="{Binding ColumnName}" Value="Name1">
                        <Setter Property="Template" Value="{StaticResource Template1}" />
                    </DataTrigger>

                    <DataTrigger Binding="{Binding ColumnName}" Value="Name2">
                        <Setter Property="Template" Value="{StaticResource Template2}" />
                    </DataTrigger>

                    ...

                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>
</DataTemplate>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 2014-03-15
    • 2012-07-02
    • 1970-01-01
    • 2018-08-13
    相关资源
    最近更新 更多