【问题标题】:Edit DataTemplate Bindings in Code Behind UWP在 UWP 后面的代码中编辑 DataTemplate 绑定
【发布时间】:2021-08-02 22:39:10
【问题描述】:

我正在尝试创建一个通用 ListView 页面,我可以在其中显示 List<object> 上的所有项目,我不知道将显示哪些字段。

我打算在导航时接收List<object> 和我想在Dictionary<string, string> 中显示的字段,其中第一个字符串表示该字段是标题、子标题或图像,第二个字符串表示名称我想作为参数绑定到 header/subheader/image 的属性。

目前我的 C# 代码如下所示:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var param = (Dictionary<string, object>)e.Parameter;
    _ItemsList = (List<object>)param["itemsList"];
    var fields = (Dictionary<string, string>)param["fields"];

    _DetailsPage = (Type)param["detailPage"];
    ObjListView.ItemsSource = UniversalAutoSuggestBox.ItemsSource = _ItemsList;
}

我的问题是数据绑定是在我的视图 XAML 上的 DataTemplate 上定义的:

 <DataTemplate x:Key="NormalItemTemplate">
            <Grid MinWidth="350"
                      Margin="5">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Ellipse Grid.Row="0" Grid.RowSpan="2"
                                 Width ="32"
                                 Height="32"
                                 Margin="6"
                                 VerticalAlignment="Center"
                                 HorizontalAlignment="Center">
                    <Ellipse.Fill>
                        <ImageBrush x:Name="LogoImage" ImageSource="{Binding Image}"/>
                    </Ellipse.Fill>
                </Ellipse>

                <TextBlock x:Name="HeaderTextBlock"
                                   Grid.Row="0" 
                                   Grid.Column="1"
                                   Text="{Binding Header}"
                                   Style="{ThemeResource BaseTextBlockStyle}"
                                   Margin="12,6,0,0"/>

                <TextBlock x:Name="FooterTextBlock" 
                           Grid.Row="1"
                                   Grid.Column="1"
                                   Text="{Binding Subheader}"
                                   Style="{ThemeResource BodyTextBlockStyle}"
                                   Margin="12,0,0,6"/>
            </Grid>
        </DataTemplate>

我想知道是否有一种方法可以动态地将数据绑定更改为从字段字典中获取的属性,以及这样做的最佳解决方案是什么,或者在那里使用不同的方法更好。

【问题讨论】:

  • 最简单的方法来显示可能将该列表绑定到 DataGrid 并让网格自动生成列的任何内容的列表。这当然不会好看。如果您想在代码中控制绑定,请查看 BindigOperations 和 Binding 类本身。至少这是 NET Framework/WPF、.NETCore/WPF 的一种方式。我对UWP一无所知。也许这里的 API 略有不同。
  • 我的问题不是更改绑定本身,而是访问它们,因为它们位于 DataTemplate 中。我不能直接直接修改 XAML 对象。
  • 加载“UI”后,您还可以访问通过模板生成的 uielements(以及它们的绑定)。但据我所知,您无法在加载 DataTemplate 之前对其进行入侵。至少没有合理的努力。
  • 另一种方法是分析每个属性的(数据)类型,并根据数据类型提供适当的模板。对于列表视图,您可以利用GridViewColumnCellTemplateSelector 属性来适当地定制数据模板。也许您需要一个绑定数据的包装器,它充当要绑定的名称的适配器,而您事先并不知道。
  • @lidqy 你不能举个例子来说明如何做到这一点吗?

标签: c# uwp


【解决方案1】:

经过一番研究,我终于找到了解决这个问题的方法。

我在 XAML 中创建 DataTemplate,但我意识到使用 XAMLReader 我可以通过从后面的代码中解析代码来做到这一点。

我创建了一个名为GenerateDataTemplate() 的函数,并在那里使用StringBuilder 的一个实例来构建XAML 代码,并在返回时使用函数ToString(),这样我就可以在一个维护字符串中获取完整的XAML 代码阅读起来有些轻松。之后,我刚刚使用了XamlReader.Load(GenerateDataTemplate()) 并将其转换为DataTemplate 并将其应用于我的ListView.ItemTemplate

我的代码:

   protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        var param = (Dictionary<string, object>)e.Parameter;
        _ItemsList = (List<object>)param["itemsList"];
        _Fields = (Dictionary<string, string>)param["fields"];

        _DetailsPage = (Type)param["detailPage"];
        ObjListView.ItemsSource = UniversalAutoSuggestBox.ItemsSource = _ItemsList;

        ObjListView.ItemTemplate = NormalItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("NormalItemTemplate"));
        SelectedItemTemplate = (DataTemplate)XamlReader.Load(GenerateDataTemplate("SelectedItemTemplate"));
    }

    public string GenerateDataTemplate(string param)
    {
        StringBuilder sbTemp = new();

        //Data Template definition
        if (param == "NormalItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"NormalItemTemplate\" ");
        if (param == "SelectedItemTemplate") sbTemp.Append("<DataTemplate x:Key=\"SelectedItemTemplate\" ");
        sbTemp.Append(@"xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" ");
        sbTemp.Append(@"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">");

        //Grid definition
        sbTemp.Append("<Grid MinWidth=\"350\" Margin=\"5\">");

        //Grid row definition
        sbTemp.Append("<Grid.RowDefinitions>");
        sbTemp.Append("<RowDefinition Height = \"*\" />");
        sbTemp.Append("<RowDefinition Height = \"*\" />");
        sbTemp.Append("<RowDefinition Height = \"*\" />");
        sbTemp.Append("</Grid.RowDefinitions>");

        //Grid column definition
        sbTemp.Append("<Grid.ColumnDefinitions>");
        sbTemp.Append("<ColumnDefinition Width = \"Auto\"/>");
        sbTemp.Append("<ColumnDefinition Width = \"*\" />");
        sbTemp.Append("</Grid.ColumnDefinitions>");

        //Ellipse definition 
        sbTemp.Append("<Ellipse Grid.Row=\"0\" Grid.RowSpan=\"2\" Width = \"32\" Height = \"32\" Margin = \"6\" VerticalAlignment = \"Center\" HorizontalAlignment = \"Center\">");
        sbTemp.Append("<Ellipse.Fill> <ImageBrush x:Name =\"LogoImage\" ImageSource = \"{Binding " + _Fields["Image"] + "}\" /> </Ellipse.Fill > ");
        sbTemp.Append("</Ellipse>");

        //Header Text Block Definition
        sbTemp.Append("<TextBlock Grid.Row = \"0\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Header"] + "}\" Style = \"{ThemeResource BaseTextBlockStyle}\" Margin = \"12,6,0,0\"/> ");

        //Subheader Text Block Definition 
        sbTemp.Append("<TextBlock  Grid.Row=\"1\" Grid.Column = \"1\" Text = \"{Binding " + _Fields["Subheader"] + "}\" Style = \"{ThemeResource BodyTextBlockStyle}\" Margin = \"12,0,0,6\" /> ");

        //Button (case Selected)
        if(param == "SelectedItemTemplate")
        {
            sbTemp.Append("<StackPanel Grid.Row=\"2\" Grid.Column=\"1\" Orientation =\"Horizontal\" HorizontalAlignment =\"Right\" Spacing = \"5\" > ");
            sbTemp.Append("<Button Content=\"Editar\" Click=\"AlterButton_Click\"/>");
            sbTemp.Append("</StackPanel>");
        }
            
        //Grid end
        sbTemp.Append("</Grid>");
        //DataTemplate end
        sbTemp.Append("</DataTemplate>");

        return sbTemp.ToString();
    }

使用这种方法,我不仅可以从我的问题中做我需要的事情,而且还可以使用更多的代码行创建第二个DataTemplate,以便选择ListView 中的项目。

现在我只需要弄清楚如何让按钮工作:)。

重要

不要忘记附加以下行:

sbTemp.Append(@"xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" ");

    sbTemp.Append(@"xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">");

如果您不附加这些,XAMLReader 将抛出 XAML Parse Error

来源: https://www.programmersought.com/article/7917516170/

https://living-sun.com/pt/xaml/866432-passing-resource-to-xamlreader-xaml-uwp.html(葡萄牙语)

希望这可以为其他人节省时间。 :)

【讨论】:

    猜你喜欢
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 2020-02-01
    • 1970-01-01
    • 2017-08-05
    • 2011-07-25
    • 1970-01-01
    相关资源
    最近更新 更多