Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
wpf在代码隐藏中应用数据模板_Wpf_Datatemplate - Fatal编程技术网

wpf在代码隐藏中应用数据模板

wpf在代码隐藏中应用数据模板,wpf,datatemplate,Wpf,Datatemplate,我正在创建一个自定义ItemsControl,其中包含用于显示任何内容的网格。我希望用户能够使用datatemplates来显示这些内容,但是我该怎么做呢 我知道如何创建模板,但我不确定如何应用模板,以使项目正确地位于网格中(我的代码),并根据用户的需要(通过datatemplate)显示每个项目 --编辑-- 我问的问题似乎有点困惑。想象一下,我想从头开始创建自己的ListView,使用网格作为布局(这不是我实际要做的,只是作为一个示例…)。如果用户提供了一个DataTemplate,我如何使

我正在创建一个自定义ItemsControl,其中包含用于显示任何内容的网格。我希望用户能够使用datatemplates来显示这些内容,但是我该怎么做呢

我知道如何创建模板,但我不确定如何应用模板,以使项目正确地位于网格中(我的代码),并根据用户的需要(通过datatemplate)显示每个项目

--编辑--


我问的问题似乎有点困惑。想象一下,我想从头开始创建自己的ListView,使用网格作为布局(这不是我实际要做的,只是作为一个示例…)。如果用户提供了一个DataTemplate,我如何使用它来确保每个网格单元中的元素都按照模板显示?

控件可以公开自己的属性,这些属性是您在代码中声明的。 如果需要一个
DataTemplate
,则可以公开类型为
DataTemplate
的属性。用户在XAML中声明控件类型时,可以提供以下模板:

<ns:YourControl>
    <ns:YourControl.DataTemplate>
        <DataTemplate>
            …
        </DataTemplate>
    </ns:YourControl.DataTemplate>
</ns:YourControl>
MyControl.xaml.cs

public partial class MyControl : UserControl
{
    public MyControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ItemTemplateProperty 
        = DependencyProperty.Register("ItemTemplate", typeof (DataTemplate), 
        typeof (MyControl), new PropertyMetadata(default(DataTemplate)));

    public DataTemplate ItemTemplate
    {
        get { return (DataTemplate) GetValue(ItemTemplateProperty); }
        set { SetValue(ItemTemplateProperty, value); }
    }

    // Other dependency properties (ItemsSource, SelectedItem, etc.)
}
消费者:

<Grid>
    <ns:MyControl ItemsSource="{Binding Items}"
                  SelectedItem="{Binding SelectedItem}">
        <ns:MyControl.ItemTemplate>
            <DataTemplate>
                <Border BorderThickness="2"
                        BorderBrush="Black">
                    <TextBlock Foreground="DarkGray"
                               Text="{Binding Name}"
                               Margin="4" />
               </Border>
            </DataTemplate>
        </ns:MyControl.ItemTemplate>
    </ns:MyControl>
</Grid>
以及背后的代码:

using System.Collections;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication1
{
  public partial class MyControl : UserControl
  {
    public MyControl()
    {
      InitializeComponent();
    }

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
      "ItemsSource", typeof (IEnumerable), typeof (MyControl), 
      new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));

    public IEnumerable ItemsSource
    {
      get { return (IEnumerable) GetValue(ItemsSourceProperty); }
      set { SetValue(ItemsSourceProperty, value); }
    }

    // This is the DataTemplate that the consumer of your control specifies
    public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
      "ItemTemplate", typeof (DataTemplate), typeof (MyControl), new PropertyMetadata(default(DataTemplate)));

    public DataTemplate ItemTemplate
    {
      get { return (DataTemplate) GetValue(ItemTemplateProperty); }
      set { SetValue(ItemTemplateProperty, value); }
    }

    // This is declared private, because it is only to be consumed by this control
    private static readonly DependencyProperty BindableItemsProperty = DependencyProperty.Register(
      "BindableItems", typeof (ObservableCollection<object>), typeof (MyControl), new PropertyMetadata(new ObservableCollection<object>()));

    private ObservableCollection<object> BindableItems
    {
      get { return (ObservableCollection<object>) GetValue(BindableItemsProperty); }
      set { SetValue(BindableItemsProperty, value); }
    }

    private static void OnItemsSourceChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
      var myControl = dependencyObject as MyControl;
      if (myControl == null)
      {
        return;
      }

      // Get reference to the Grid using reflection. You could also walk the tree.
      var grid = (Grid) typeof (ItemsControl).InvokeMember("ItemsHost",
        BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
        null, myControl.ItemsControl, null);

      var columns = grid.ColumnDefinitions;
      columns.Clear();
      myControl.BindableItems.Clear();

      var items = args.NewValue as IEnumerable;
      if (items != null)
      {
        var columnIndex = 0;
        foreach (var item in items)
        {
          columns.Add(new ColumnDefinition{ Width = GridLength.Auto });
          var container = new MyItem
          {
            Row = columnIndex,
            Column = columnIndex++,
            Content = item
          };
          myControl.BindableItems.Add(container);
        }
      }
    }
  }

  public class MyItem
  {
    public object Content { get; set; }
    public int Row { get; set; }
    public int Column { get; set; }
  }
}
使用系统集合;
使用System.Collections.ObjectModel;
运用系统反思;
使用System.Windows;
使用System.Windows.Controls;
命名空间WpfApplication1
{
公共部分类MyControl:UserControl
{
公共MyControl()
{
初始化组件();
}
公共静态只读DependencyProperty项SourceProperty=DependencyProperty.Register(
“ItemsSource”、typeof(IEnumerable)、typeof(MyControl),
新属性元数据(默认值(IEnumerable),OnItemSourceChanged);
公共IEnumerable ItemsSource
{
get{return(IEnumerable)GetValue(ItemsSourceProperty);}
set{SetValue(ItemsSourceProperty,value);}
}
//这是控件使用者指定的数据模板
公共静态只读DependencyProperty ItemTemplateProperty=DependencyProperty.Register(
“ItemTemplate”、typeof(DataTemplate)、typeof(MyControl)、新PropertyMetadata(默认值(DataTemplate));
公共数据模板ItemTemplate
{
获取{return(DataTemplate)GetValue(ItemTemplateProperty);}
set{SetValue(ItemTemplateProperty,value);}
}
//这被声明为私有,因为它只能由该控件使用
私有静态只读DependencyProperty BindableItemsProperty=DependencyProperty.Register(
“BindableItems”、typeof(ObservableCollection)、typeof(MyControl)、new PropertyMetadata(new ObservableCollection());
私有可观察集合可绑定项
{
get{return(ObservableCollection)GetValue(BindableItemsProperty);}
set{SetValue(BindableItemsProperty,value);}
}
私有静态资源已更改(DependencyObject DependencyObject,DependencyPropertyChangedEventArgs args)
{
var myControl=作为myControl的dependencyObject;
if(myControl==null)
{
返回;
}
//使用反射获取对网格的引用。您还可以在树上漫游。
var grid=(grid)typeof(ItemsControl).InvokeMember(“ItemsHost”,
BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
null,myControl.ItemsControl,null);
var columns=grid.ColumnDefinitions;
columns.Clear();
myControl.BindableItems.Clear();
var items=args.NewValue作为IEnumerable;
如果(项!=null)
{
风险价值指数=0;
foreach(项目中的var项目)
{
Add(新的ColumnDefinition{Width=GridLength.Auto});
var container=newmyitem
{
行=列索引,
Column=columnIndex++,
内容=项目
};
myControl.BindableItems.Add(容器);
}
}
}
}
公共类MyItem
{
公共对象内容{get;set;}
公共int行{get;set;}
公共int列{get;set;}
}
}

使用DataTemplateSelector选择模板。不要做代码隐藏的事情。正确学习WPF并使用正确的XAML和DataBinding@HighCore请提供更有用的评论。我对我的问题进行了编辑,以便对我正在做的事情进行更多的澄清。如果你能告诉我如何通过XAML做到这一点,那就太好了。如果我已经知道怎么做,我就不会在这里问这个问题。@ryan0270我不能提供完整的答案,因为我现在很忙。我有上百个答案解释了如何正确使用WPF,而不是代码隐藏的东西(我可以用它将你的问题标记为重复并关闭它)。搜索我的答案历史记录或谷歌“stackoverflow highcore delete all your code”(删除所有代码),你就会得到它。让我们先尝试成为一个有帮助的社区,然后再尝试成为一个坚持者。正如我们所知,向自定义控件添加属性意味着在代码隐藏中工作;OP试图了解所有的片段是如何连接在一起的。如果你发现一个真正相关的重复问题,并有一个像样的答案,请发布一个链接。对不起,但我仍然感到困惑。首先,绑定的一端有DataTemplate,但另一端有什么?其次,如果控件的ItemsSource绑定到字符串列表,例如,如何通过模板传递每个字符串,然后将其显示在相应的网格单元中?@ryan0270我添加了一个示例以供参考。如果这无助于澄清问题,请告诉我。您没有在UI元素中放置常规CLR属性。你的代码错了。请改用适当的DependencyProperties。顺便说一句,看起来您正在重新设计
ItemsControl
。没有必要这样做。这是一个明确的例子,因为我不知道OP的确切用例。我仍然不知道如何做布局。如何指定将datatemplate应用于第一个源项的结果应该放在网格的单元格(0,0)中
<UserControl x:Class="WpfApplication1.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" 
             x:Name="ThisControl"
             d:DesignHeight="300" d:DesignWidth="300">
    <ItemsControl x:Name="ItemsControl"
                  ItemsSource="{Binding BindableItems, ElementName=ThisControl, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="{x:Type ContentPresenter}">
                <Setter Property="Grid.Row" Value="{Binding Row}" />
                <Setter Property="Grid.Column" Value="{Binding Column}" />
                <Setter Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <ContentPresenter Content="{Binding Content}"
                                              ContentTemplate="{Binding ItemTemplate, ElementName=ThisControl}" />
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</UserControl>
using System.Collections;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication1
{
  public partial class MyControl : UserControl
  {
    public MyControl()
    {
      InitializeComponent();
    }

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
      "ItemsSource", typeof (IEnumerable), typeof (MyControl), 
      new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));

    public IEnumerable ItemsSource
    {
      get { return (IEnumerable) GetValue(ItemsSourceProperty); }
      set { SetValue(ItemsSourceProperty, value); }
    }

    // This is the DataTemplate that the consumer of your control specifies
    public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
      "ItemTemplate", typeof (DataTemplate), typeof (MyControl), new PropertyMetadata(default(DataTemplate)));

    public DataTemplate ItemTemplate
    {
      get { return (DataTemplate) GetValue(ItemTemplateProperty); }
      set { SetValue(ItemTemplateProperty, value); }
    }

    // This is declared private, because it is only to be consumed by this control
    private static readonly DependencyProperty BindableItemsProperty = DependencyProperty.Register(
      "BindableItems", typeof (ObservableCollection<object>), typeof (MyControl), new PropertyMetadata(new ObservableCollection<object>()));

    private ObservableCollection<object> BindableItems
    {
      get { return (ObservableCollection<object>) GetValue(BindableItemsProperty); }
      set { SetValue(BindableItemsProperty, value); }
    }

    private static void OnItemsSourceChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
      var myControl = dependencyObject as MyControl;
      if (myControl == null)
      {
        return;
      }

      // Get reference to the Grid using reflection. You could also walk the tree.
      var grid = (Grid) typeof (ItemsControl).InvokeMember("ItemsHost",
        BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
        null, myControl.ItemsControl, null);

      var columns = grid.ColumnDefinitions;
      columns.Clear();
      myControl.BindableItems.Clear();

      var items = args.NewValue as IEnumerable;
      if (items != null)
      {
        var columnIndex = 0;
        foreach (var item in items)
        {
          columns.Add(new ColumnDefinition{ Width = GridLength.Auto });
          var container = new MyItem
          {
            Row = columnIndex,
            Column = columnIndex++,
            Content = item
          };
          myControl.BindableItems.Add(container);
        }
      }
    }
  }

  public class MyItem
  {
    public object Content { get; set; }
    public int Row { get; set; }
    public int Column { get; set; }
  }
}