在代码后台创建数据模板

3

我正在尝试创建一个 ListBox 视图来显示数据,并且我希望它包含一个带有 datatemplate 的 ListBox,用于显示两列“产品 ID 和产品条形码”。

我想要使用纯 C# 代码创建它,或者如果可能的话,通过 xaml 加载它? 如果我可以创建一个模板,我可以将其作为某种资源在 c# 中获取。

目前我所做的是: 在 XAML 中:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="37*" />
        <RowDefinition Height="88*" />
    </Grid.RowDefinitions>
    <TextBlock Text="Type Your Search :" HorizontalAlignment="Left"  VerticalAlignment="Bottom" Width="112" Height="15.96" Margin="20,0,0,4" />

    <TextBox HorizontalAlignment="Right" VerticalAlignment="Bottom" Height="25" Width="300" Margin="0,0,44,0" x:Name="txtCAuto" TextWrapping="NoWrap" HorizontalContentAlignment="Right" />

    <ListBox x:Name="lbSuggestion" SelectionChanged="lbSuggestion_SelectionChanged" Foreground="Black" Width="300" Margin="0,0,44,0"  FlowDirection="RightToLeft" Background="LightYellow" Grid.Row="1" Visibility="Collapsed"  ScrollViewer.HorizontalScrollBarVisibility="Auto" ItemsSource="{Binding}"  HorizontalAlignment="Right" VerticalAlignment="Top" HorizontalContentAlignment="Right" BorderBrush="Transparent"  Grid.IsSharedSizeScope="True">
    </ListBox>
</Grid>

在代码后台:

string typedString = txtCAuto.Text.ToUpper();
        List<string> autoList = new List<string>();
        autoList.Clear();

         prodDetails ps = SelProd4Sale();

        foreach (string item in ps.ProdBrcdList)
        {
            if (!string.IsNullOrEmpty(txtCAuto.Text))
            {
                if (item.StartsWith(typedString))
                {
                    //autoList.Add(item);
                    FrameworkElementFactory colProdID = new FrameworkElementFactory(typeof(TextBlock));
                    Binding prodID = new Binding(ps.ProdIDList.ToString());
                    colProdID.SetBinding(TextBlock.TextProperty, prodID);

                    FrameworkElementFactory colProdBarcode = new FrameworkElementFactory(typeof(TextBlock));
                    Binding prodBarcode = new Binding();
                    prodBarcode.Path = new PropertyPath(ps.ProdBrcdList.ToString());
                    colProdBarcode.SetBinding(TextBlock.TextProperty, prodBarcode);


                    FrameworkElementFactory sb = new FrameworkElementFactory(typeof(StackPanel));
                    sb.AppendChild(colProdID);
                    sb.AppendChild(colProdBarcode);

                    dTemplate = new DataTemplate { VisualTree = sb };
                    dTemplate.Seal();


                }
            }
        }

        if (autoList.Count > 0)
        {
            lbSuggestion.ItemTemplate = dTemplate;
            //lbSuggestion.ItemsSource = autoList;
            lbSuggestion.Visibility = Visibility.Visible;
        }
        else if (txtCAuto.Text.Equals(""))
        {
            lbSuggestion.Visibility = Visibility.Collapsed;
            lbSuggestion.ItemsSource = null;
        }
        else
        {
            lbSuggestion.Visibility = Visibility.Collapsed;
            lbSuggestion.ItemsSource = null;
        }

但是没有数据出现,请问有什么建议吗? 谢谢。

如果你要在代码后端完成它,为什么不创建一个自定义的 ListBoxItem - sa_ddam213
为什么要写那么多代码,如果可以在XAML中完成呢? - Paritosh
当我尝试在XAML中实现它时,也没有数据显示,所以我尝试在代码后台中实现。 - Love_Egypt
3个回答

8
你可以在XAML中定义资源,并在代码后台检索它,如果它有一个已定义的。
在你的XAML中:
<DataTemplate x:Key="anyId">...</DataTemplate>

在你的代码后台中:
var dataTemplate = Application.Current.TryFindResource("anyId") as DataTemplate;

或者

var dataTemplate = Application.Current.FindResource("anyId") as DataTemplate;

1
你需要在XAML文件的资源字典中编写DataTemplate,并自己设置x:Key!我的意思是,你只需设置一个x:Key参数即可在代码后台检索任何资源。 - Sisyphe
好的答案。它允许您在 XAML 中定义数据模板,然后在必要时使用它。 - Josh

4
我已经创建了这样的DataTemplate:

代码如下:

private DataTemplate getDataTemplate()
{
    DataTemplate retVal = null;
    String markup = String.Empty;

    markup = "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:local=\"clr-namespace:YOUR.PROJECT.NAMESPACE;assembly=YOUR.PROJECT.NAMESPACE\">";
    markup += "<Grid>";
    markup += "<TextBlock Text=\"{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Content, Mode=OneWay}\" />";
    markup += "</Grid>";
    markup += "</DataTemplate>";

    retVal = (DataTemplate)XamlReader.Load(markup);

    return retVal;
}

然后在需要的地方(例如OnApplyTemplate),调用此方法。

this.ContentTemplate = getDataTemplate();

注意:您可能需要更改WPF的“xmlns”,因为此示例取自我的其中一个Silverlight项目。但是,其思想是相同的。


1
一个注释是,在我看来最好的做法是在XAML中创建它,但是由于问题是这样的,我选择了用代码来说明它是如何完成的 :-) - Mats Magnem
当我尝试在XAML中创建它时,没有数据显示,所以请在代码后台完成。 - Love_Egypt

1

条件XAML数据模板

在对象的XAML文件中定义静态DataTemplate是通常的方法。此外,Microsoft提供的DataTemplate.LoadContent()示例非常巧妙地展示了如何在运行时动态切换模板(参见DataTemplate.LoadContent method)。

然而,如果你有一个特殊需求,需要进行条件XAML编译(比如在构建发布版本时省略仅用于调试的XAML),则需要采用XamlReader.Load()方法(参见XamlReader.Load method)。

为此,我认为更详细的示例可能会有所帮助。这里,我有一个仅在Debug模式下需要的ListView,它绑定到一个自定义对象的ObservableCollection<>。由于仅在Debug模式下需要,因此ListView不是在静态XAML中定义的...


自定义类:
    class ActiveNotification
    {
        public String Name { get; set; }
        public String Type { get; set; }
        public String DayOfWeek { get; set; }
        public DateTime DeliveryTime { get; set; }
        public String Id { get; set; }
    }

私有成员变量:
    readonly ObservableCollection<ActiveNotification> _activeNotifications = new ObservableCollection<ActiveNotification>();
    readonly ListView listViewNotifications = 
        new ListView 
        { 
            Visibility = Visibility.Collapsed,
            HorizontalAlignment = HorizontalAlignment.Left,
            VerticalAlignment = VerticalAlignment.Bottom,
        };

加载时列表视图设置:

        // Set up notifications list
        listViewNotifications.SetBinding(ListView.ItemsSourceProperty, new Binding { Source = _activeNotifications });
        listViewNotifications.Tapped += listViewNotifications_Tapped;
        Grid.SetRowSpan(listViewNotifications, 2);
        Grid.SetColumnSpan(listViewNotifications, 2);
        var xamlString =
            "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">" +
                "<StackPanel Orientation=\"Horizontal\" VerticalAlignment=\"Center\">" +
                    "<TextBlock Text=\"{Binding Name}\" Margin=\"20,0,10,0\"/>" +
                    "<TextBlock Text=\"{Binding Type}\" Margin=\"0,0,10,0\"/>" +
                    "<TextBlock Text=\"{Binding DayOfWeek}\" Margin=\"0,0,10,0\"/>" +
                    "<TextBlock Text=\"{Binding DeliveryTime}\" Margin=\"0,0,10,0\"/>" +
                    "<TextBlock Text=\"{Binding Id}\"/>" +
                "</StackPanel>" +
            "</DataTemplate>";
        var dataTemplate = (DataTemplate)XamlReader.Load(xamlString);
        listViewNotifications.ItemTemplate = dataTemplate;
        GridMain.Children.Add(listViewNotifications);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接