【问题标题】:DataTemplated DataGrid not binding correctly? DataTemplateSelector.SelectTemplate receives null as "item"DataTemplated DataGrid 没有正确绑定? DataTemplateSelector.SelectTemplate 接收 null 作为“项目”
【发布时间】:2019-11-01 22:01:31
【问题描述】:

所以我尝试使用 DataTemplateSelector 制作自定义样式的 DataGrid。我是 WPF 和绑定的新手,所以我可能做错了什么。

作为 SelectTemplate 函数的参数接收的项目对象始终为空。

我试过用谷歌搜索这个问题,但找不到答案。

XAML:

        <Grid.Resources>
            <!-- Default DataTemplate -->
            <DataTemplate x:Key="DefaultDataTemplate">
                <TextBlock Text="{Binding Path=Value}" />
            </DataTemplate>

            <!-- DataTemplate for Booleans -->
            <DataTemplate x:Key="BooleanDataTemplate">
                <CheckBox IsChecked="{Binding Path=Value, Mode=TwoWay}" />
            </DataTemplate>

            <!-- DataTemplate for Arrays -->
            <DataTemplate x:Key="ArrayDataTemplate">
                <ComboBox ItemsSource="{Binding Path=Value, Mode=TwoWay}" />
            </DataTemplate>

            <local:ValueDataTemplateSelector x:Key="templateSelector" 
                   DefaultDataTemplate="{StaticResource DefaultDataTemplate}" 
                   BooleanDataTemplate="{StaticResource BooleanDataTemplate}" 
                   ArrayDataTemplate="{StaticResource ArrayDataTemplate}" />

        </Grid.Resources>

        <DataGrid Name="DG1" ItemsSource="{Binding TagListView}" AutoGenerateColumns="False" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" />
                <DataGridTemplateColumn Header="Value" CellTemplateSelector="{StaticResource templateSelector}" CellEditingTemplateSelector="{StaticResource templateSelector}" />
            </DataGrid.Columns>
        </DataGrid>

后面的代码:

    public partial class TestView : Window
    {
        public TestView()
        {
            var t = new TestViewModel();
            DataContext = t;
            InitializeComponent();


        }
    }

视图模型:

    class TestViewModel
    {

        public TestViewModel()
        {
            generateTestList();
            TagListView = new ListCollectionView(testList);
        }

        private ObservableCollection<TestTag> testList;

        private void generateTestList()
        {
            testList = new ObservableCollection<TestTag>();

            bool b = false;
            testList.Add(new TestTag("bool", (object)b, b.GetType()));

            string s = "...";
            testList.Add(new TestTag("string", (object)s, s.GetType()));

            ushort ui = (ushort)100u;
            testList.Add(new TestTag("uint16", (object)ui, ui.GetType()));

            int[] i_arr = new int[] { 1, 2, 3 };
            testList.Add(new TestTag("int[]", (object)i_arr, i_arr.GetType()));



        }
        public ListCollectionView TagListView { get; private set; }
}

数据模板选择器。 SelectTemplate 的“item”参数始终为空

public class ValueDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate DefaultDataTemplate { get; set; }
        public DataTemplate BooleanDataTemplate { get; set; }
        public DataTemplate ArrayDataTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var tag = item as TestTag;

            Type t = tag.Type;

            if (t == typeof(bool))
                return BooleanDataTemplate;

            if (t == typeof(int[]))
                return ArrayDataTemplate;

            return DefaultDataTemplate;
        }
    }

模型

    class TestTag : INotifyPropertyChanged
    {

        private string _Name;
        private object _Value;
        public Type Type;

        public string Name
        {
            get { return _Name; }
            private set
            {
                _Name = value;
                NotifyPropertyChanged("Name");
            }
        }

        public object Value
        {
            get
            {
                return _Value;
            }

            set
            {
                _Value = value;
                NotifyPropertyChanged("Value");
            }
        }

【问题讨论】:

    标签: c# wpf datagrid


    【解决方案1】:

    看起来您只是缺少对 SelectTemplate 方法的空检查:

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                var tag = item as TestTag;
                if(tag == null)
                    return DefaultDataTemplate;
                Type t = tag.Type;
                if (t == typeof(bool))
                    return BooleanDataTemplate;
                if (t == typeof(int[]))
                    return ArrayDataTemplate;
                return DefaultDataTemplate;
            }
    

    您不妨考虑对您的 TestTag 模型类进行一些清理,例如使用泛型而不是 Object 类型,丢失 Type 属性并在需要时使用 typeof ...

    【讨论】:

    • 非常感谢。空测试确实解决了问题;窗口现在加载并且值列看起来如预期。但是“名称”列是空的,但这是一个不同的问题。
    • 关于模型类;真正的(“Tag”,而不是“TestTag”)模型类由基本上发布 (object variable, typeof(variable)) 的服务器填充,我希望所有“Tags”都聚集在同一个 ObservableCollection 中。你仍然认为泛型是一个很好的解决方案吗?你有一些我可以阅读的链接来研究这个问题吗?
    • @jcberg 用于 Name 列,问题在于您只是设置了 Header 列但您没有将其绑定到模型中的特定属性,这是一个简单的修复:&lt;DataGridTextColumn Header="Name" Binding="{Binding Name}" /&gt;跨度>
    • @jcberg for your Tag 类我仍然认为将变量的类型存储在属性中是多余的,通用或基类以及每种类型的特定子类在这里看起来更合适。由于多态性,您始终可以将所有项目放在同一个集合中。
    • 再次感谢,您的 Name 列解决方案比我的要优雅得多。我还尝试按照您的建议改进模型(现在是实现 ITestTag 的 TestTag)并且效果非常好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 2011-03-28
    • 1970-01-01
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多