开发者

Why doesn't this datatemplate work at designtime?

The following simple datatemplate only works at runtime. At designtime it displays nothing. Why is this so?

<DataTemplate x:Key="SomeEnumDataTemplate">
    <ListBox Name="list" Width="20" IsSynchronizedWithCurrentItem="True" SelectedIndex="{Binding Mode=OneWay, Converter={StaticResource EnumToIntConverter}}">
        <ListBox.Template>
            <ControlTemplate TargetType="ListBox">
                <ContentPresenter Content="{TemplateBinding SelectedItem}" />
            </ControlTemplate>
        </ListBox.Template>
        <Rectangle Height="10" Width="10" Fill="Red" />
        <Rectangle Height="10" Width="10" Fill="Green" />
        <Rectangle Height="10" Width="10" Fill="Yellow" />
    </ListBox>
</DataTemplate>

I use it like this in another DataTemplate:

<HierarchicalDataTemplate x:Key="NodeDataTemplate" ItemsSource="{Binding Children}">
    <StackPanel Orientation="Horizontal" ToolTip="{Binding Description}">            
        <ContentControl ContentTemplate="{StaticResource SomeEnumDataTemplate}" Content="{Binding Mode}" Margin="3,0,0,0" />
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</HierarchicalDataTemplate>

Which again is used in a UserControl that has design-time data:

<UserControl x:Class="MyProject.Views.MyView"
             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" xmlns:ViewModels="clr-namespace:MyProject.ViewModels" mc:Ignorable="d" 
             d:DesignHeight="780" d:DesignWidth="400" d:DataContext="{x:Static ViewModels:SampleData.RootNode}">     
 <TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource NodeDataTemplate}">
     <TreeView.ItemContainerStyle>
  开发者_如何学Go    <Style TargetType="TreeViewItem">
       <Setter Property="IsExpanded" Value="True" />
   </Style>   
  </TreeView.ItemContainerStyle>
 </TreeView>
</UserControl>


You can easily create design time data:

  1. Create your DataModel:

    public class Person
    {
        public string Name { get; set; }
    
        public int  Age { get; set; }
    }
    
    public class PersonCollection : List<Person>
    {
        public PersonCollection()
        {
    
        }
    }
    
  2. Create a file with .xaml extension containing:

DesignTimeTreeData.xaml

    <local:PersonCollection xmlns:local="clr-namespace:Test_TreeWithDesignData">
        <local:Person Name="Joan Solo" Age="32" />
        <local:Person Name="Amara Skywalker" Age="31" />
    </local:PersonCollection>
  1. Use the d:DataContext and d:DesignData to use the data you specified in the DesignTimeTreeData.xaml:

MainWindow.xaml

    <Window x:Class="Test_TreeWithDesignData.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Test_TreeWithDesignData"
            Title="MainWindow"
            Height="350"
            Width="525"
            mc:Ignorable="d">
        <Grid>
            <TreeView
                d:DataContext="{d:DesignData Source=./DesignTimeTreeData.xaml}"
                ItemsSource="{Binding}">
                <TreeView.Resources>
                    <DataTemplate DataType="{x:Type local:Person}" >
                        <StackPanel Orientation="Horizontal" Height="25">
                            <Label Content="{Binding Name}"/>
                            <Label Content="{Binding Age}" Margin="3,0,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </TreeView.Resources>
            </TreeView>
        </Grid>
    </Window>
  1. Since tipically the Window.DataContext property is set to a ViewModel and the TreeView.DataContext is a collection of it, in order yo keep both datasources working, you can surround the TreeView with a Grid which DataContext is set to the ViewModel's collection.

DummyViewModel.cs

    public class DummyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public PersonCollection Persons { get; set; }

        public DummyViewModel()
        {
            this.Persons = new PersonCollection();
        }
    }

MainWindow.xaml

    <Window x:Class="Test_TreeWithDesignData.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Test_TreeWithDesignData"
            Title="MainWindow"
            Height="350"
            Width="525"
            mc:Ignorable="d">
        <Window.DataContext>
            <local:DummyViewModel />
        </Window.DataContext>

        <Grid Name="RootGrid">
            <Grid Name="TreeGrid" DataContext="{Binding Persons}">
                <TreeView d:DataContext="{d:DesignData Source=./DesignTimeTreeData.xaml}"
                    ItemsSource="{Binding}">
                    <TreeView.Resources>
                        <DataTemplate DataType="{x:Type local:Person}" >
                            <StackPanel Orientation="Horizontal" Height="25">
                                <Label Content="{Binding Name}"/>
                                <Label Content="{Binding Age}" Margin="3,0,0,0"/>
                            </StackPanel>
                        </DataTemplate>
                    </TreeView.Resources>
                </TreeView>
            </Grid>
        </Grid>
    </Window>

Result:

Why doesn't this datatemplate work at designtime?

Edit

The next question is going to be: Ho do I expand the items in the Designer?

  1. The Person is going to have a collection of persons:

    public class Person
    {
        public string Name { get; set; }
    
        public int  Age { get; set; }
    
        public PersonCollection Childs { get; set; }
    }
    
  2. The design time data is going to have a child

DesignTimeTreeData.xaml

    <local:PersonCollection xmlns:local="clr-namespace:Test_TreeWithDesignData">
        <local:Person Name="Joan Solo" Age="32" />
        <local:Person Name="Amara Skywalker" Age="31">
            <local:Person.Childs>
                <local:PersonCollection>
                    <local:Person Name="Han Skywalker" Age="10" />
                </local:PersonCollection>
            </local:Person.Childs>
        </local:Person>
    </local:PersonCollection>
  1. The tree is going to have a HierarchicalDataTemplate now:

    <HierarchicalDataTemplate
        DataType="{x:Type local:Person}"
        ItemsSource="{Binding Childs}">
        <StackPanel Orientation="Horizontal" Height="25">
            <Label Content="{Binding Name}"/>
            <Label Content="{Binding Age}" Margin="3,0,0,0"/>
        </StackPanel>
    </HierarchicalDataTemplate>
    
  2. And the TreeView will bind to the DesignerProperties.IsInDesignMode to expand the items in the designer:

    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Style.Triggers>
                <DataTrigger
                        Binding="{Binding RelativeSource={RelativeSource Self}, Path=(pf:DesignerProperties.IsInDesignMode)}"
                        Value="true"
                        >
                    <Setter Property="IsExpanded" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TreeView.ItemContainerStyle>
    

This is the xaml for the window:

MainWindow.xaml

    <Window x:Class="Test_TreeWithDesignData.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Test_TreeWithDesignData"
            xmlns:pf="clr-namespace:System.ComponentModel;assembly=PresentationFramework"
            Title="MainWindow"
            Height="250"
            Width="325"
            mc:Ignorable="d"
            >
        <Window.DataContext>
            <local:DummyViewModel />
        </Window.DataContext>

        <Grid Name="RootGrid">

            <Grid Name="TreeGrid" DataContext="{Binding Persons}">
                <TreeView
                    d:DataContext="{d:DesignData Source=./DesignTimeTreeData.xaml}"
                    ItemsSource="{Binding}"
                    >
                    <TreeView.ItemContainerStyle>
                        <Style TargetType="TreeViewItem">
                            <Style.Triggers>
                                <DataTrigger
                                        Binding="{Binding RelativeSource={RelativeSource Self}, Path=(pf:DesignerProperties.IsInDesignMode)}"
                                        Value="true"
                                        >
                                    <Setter Property="IsExpanded" Value="True" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TreeView.ItemContainerStyle>
                    <TreeView.Resources>
                        <HierarchicalDataTemplate
                            DataType="{x:Type local:Person}"
                            ItemsSource="{Binding Childs}"
                            >
                            <StackPanel Orientation="Horizontal" Height="25">
                                <Label Content="{Binding Name}"/>
                                <Label Content="{Binding Age}" Margin="3,0,0,0"/>
                            </StackPanel>
                        </HierarchicalDataTemplate>
                    </TreeView.Resources>
                </TreeView>
            </Grid>
        </Grid>
    </Window>

And this is the result:

Why doesn't this datatemplate work at designtime?


Once you start Binding, setting DataContext, ItemSource etc, the designer will crap out on you. just remove all your bindings (looks like 3) and your designer will work. Get it all lined up, or whatever you need to do, then add bindings back.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜