2013-12-10 32 views
3

我试图做一个PropertyGrid的自定义控件。 PropertyGrid将与Visual Studio中使用的PropertyGrid非常相似。我已经尝试过使用扩展WPF工具包的PropertyGrid,但是您必须指定属性的类别和属性,我们需要更改类别运行时。据我所知,这是不可能的属性。在一个ItemsControl的网格中的Gridsplitter

所以我自己制作PropertyGrid。这是到目前为止我的代码:

的Generic.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:HomeMadePropertyGrid" 
        xmlns:System="clr-namespace:System;assembly=mscorlib"> 

    <BooleanToVisibilityConverter x:Key="BoolToVisConverter"></BooleanToVisibilityConverter> 
    <SolidColorBrush x:Key="GlyphBrush" Color="#444" /> 
    <ControlTemplate x:Key="toggleButtonTemplate" TargetType="ToggleButton"> 
     <Grid Width="15" Height="13" Background="Transparent"> 
      <Path x:Name="ExpandPath" Fill="{StaticResource GlyphBrush}" Data="M 4 0 L 8 4 L 4 8 Z" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="1,1,1,1" /> 
     </Grid> 
     <ControlTemplate.Triggers> 
      <Trigger Property="IsChecked" Value="True"> 
       <Setter Property="Data" TargetName="ExpandPath" Value="M 0 4 L 8 4 L 4 8 Z"/> 
      </Trigger> 
     </ControlTemplate.Triggers> 
    </ControlTemplate> 
    <Style x:Key="toggleButtonStyle" TargetType="ToggleButton"> 
     <Setter Property="Template" Value="{StaticResource toggleButtonTemplate}" /> 
    </Style> 

    <Style TargetType="{x:Type local:PropertyGrid}"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type local:PropertyGrid}"> 
        <Border Background="{TemplateBinding Background}" 
          BorderBrush="{TemplateBinding BorderBrush}" 
          BorderThickness="{TemplateBinding BorderThickness}"> 
         <ItemsControl ItemsSource="{TemplateBinding ItemsSource}"> 
          <ItemsControl.ItemsPanel> 
           <ItemsPanelTemplate> 
            <VirtualizingStackPanel/> 
           </ItemsPanelTemplate> 
          </ItemsControl.ItemsPanel> 
          <ItemsControl.ItemTemplate> 
           <DataTemplate> 
            <StackPanel Background="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}"> 
             <StackPanel Orientation="Horizontal"> 
              <ToggleButton x:Name="toggleButton" Height="20" Width="20" Style="{StaticResource toggleButtonStyle}"/> 
              <TextBlock Text="{Binding Name}" FontWeight="Bold"></TextBlock> 
             </StackPanel> 
             <ItemsControl ItemsSource="{Binding Items}"> 
              <ItemsControl.ItemTemplate> 
               <DataTemplate> 
                <Grid Visibility="{Binding ElementName=toggleButton, Path=IsChecked, Converter={StaticResource BoolToVisConverter}}" 
                  Grid.IsSharedSizeScope="True"> 

                 <Grid.ColumnDefinitions> 
                  <ColumnDefinition Width="*"/> 
                  <ColumnDefinition Width="Auto" /> 
                  <ColumnDefinition Width="*"/> 
                 </Grid.ColumnDefinitions> 

                 <Border BorderThickness="1" BorderBrush="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}"> 
                  <TextBlock Background="White" Text="{Binding Path=Name}"/> 
                 </Border> 
                 <GridSplitter Width="1" 
                     Grid.RowSpan="4" Grid.Column="1" 
                     HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                     Background="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}"/> 
                 <Border Grid.Column="2" BorderThickness="1" BorderBrush="{Binding GridColor, RelativeSource={RelativeSource AncestorType=local:PropertyGrid}}"> 
                  <ContentPresenter Grid.Column="2" Content="{Binding Value}"> 
                   <ContentPresenter.Resources> 
                    <DataTemplate DataType="{x:Type System:String}"> 
                     <TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" 
                      BorderThickness="0"/> 
                    </DataTemplate> 
                    <DataTemplate DataType="{x:Type System:Int32}"> 
                     <TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" 
                      TextAlignment="Right" 
                      BorderThickness="0"/> 
                    </DataTemplate> 
                    <DataTemplate DataType="{x:Type System:Double}"> 
                     <TextBox Text="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" 
                      TextAlignment="Right" 
                      BorderThickness="0"/> 
                    </DataTemplate> 
                    <DataTemplate DataType="{x:Type System:Boolean}"> 
                     <CheckBox IsChecked="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" 
                        HorizontalAlignment="Center"/> 
                    </DataTemplate> 
                   </ContentPresenter.Resources> 
                  </ContentPresenter> 
                 </Border> 
                </Grid> 
               </DataTemplate> 
              </ItemsControl.ItemTemplate> 
             </ItemsControl> 
            </StackPanel> 
           </DataTemplate> 
          </ItemsControl.ItemTemplate> 
         </ItemsControl> 
        </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</ResourceDictionary> 

PropertyGrid.cs

public class PropertyGrid : ItemsControl 
{ 
    public Brush GridColor 
    { 
     get { return (Brush)GetValue(GridColorProperty); } 
     set { SetValue(GridColorProperty, value); } 
    } 

    public static readonly DependencyProperty GridColorProperty = 
     DependencyProperty.Register("GridColor", typeof(Brush), typeof(PropertyGrid), new UIPropertyMetadata(new SolidColorBrush(Colors.Transparent))); 

    static PropertyGrid() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(PropertyGrid), new FrameworkPropertyMetadata(typeof(PropertyGrid))); 
    } 
} 

的PropertyGroup

public class PropertyGroup 
{ 
    public string Name { get; set; } 
    public List<PropertyGridItem> Items { get; set; } 

    public PropertyGroup() 
    { 
     Items = new List<PropertyGridItem>(); 
     Name = ""; 
    } 
} 

PropertyGridItem

public class PropertyGridItem 
{ 
    public string Name { get; set; } 
    public object Value { get; set; } 

    public PropertyGridItem(string propertyName, object propertyValue) 
    { 
     Name = propertyName; 
     Value = propertyValue; 
    } 
} 

这段代码在我MainWindow.xaml:

<local:PropertyGrid ItemsSource="{Binding Path=Groups}" GridColor="#f0f0f0"/> 

我的视图模型的背后代码:

public MainWindow() 
{ 
    InitializeComponent(); 
    this.DataContext = new ViewModel(); 
} 

视图模型

public class ViewModel 
{ 
    public List<PropertyGroup> Groups { get; set; } 

    public ViewModel() 
    { 
     Groups = new List<PropertyGroup>(); 

     PropertyGroup group1 = new PropertyGroup(); 
     group1.Name = "Group1"; 
     group1.Items.Add(new PropertyGridItem("Item1", "test")); 
     group1.Items.Add(new PropertyGridItem("Item2", 300)); 
     group1.Items.Add(new PropertyGridItem("Item3", true)); 
     group1.Items.Add(new PropertyGridItem("Item4", 5.2)); 
     Groups.Add(group1); 

     PropertyGroup group2 = new PropertyGroup(); 
     group2.Name = "Group2"; 
     group2.Items.Add(new PropertyGridItem("Item1", "test")); 
     group2.Items.Add(new PropertyGridItem("Item2", 300)); 
     group2.Items.Add(new PropertyGridItem("Item3", true)); 
     group2.Items.Add(new PropertyGridItem("Item4", 5.2)); 
     Groups.Add(group2); 
    } 
} 

我遇到的问题是,GridSplitter应用于每一行。我希望GridSplitter应用于组的所有行。我知道这是因为我为每个项目制作一个新的网格。对于附加的属性来说,项目必须是网格的直接子节点。 DataGrid也不是一个选项,因为GridSplitter仅在列标题之间可用。

所以长话短说:如何在ItemsControl中使用GridSplitter的Grid,该GridSplitter适用于理想情况下所有组或整个Grid的所有行(如果这是不可能的话)。

+0

它的一切我所需要的!你能分享你的代码的源代码吗? –

+0

@ twister0k我的问题和答案已共享是几乎所有我可以分享。有了这个代码,你应该可以做出一个简单的属性网格。有什么问题可以帮我解决吗? – Martijn

+0

感谢您的回答。我根据你的代码做了一个简单的项目,但是,我不知道为什么,它不起作用。如果你有时间,请参见[代码](https://github.com/twister0k/propertyGridwpf) –

回答

3

我终于找到了解决这个问题。

为了得到这个工作,我必须:

  • 的Grid.IsSharedSizeScope设置为true父的ItemsControl。
  • 使用任意名称在名称列上设置SharedSizeGroup属性。
  • 删除名称列上的星号。同时具有与明星上浆第一和第三列导致某种原因卡住GridSplitter。
  • 在GridSplitter上设置固定宽度,我将宽度设置为2.
  • 将GridSplitter的ResizeBehaviour设置为PreviousAndNext。

这里有一个相关的部分结果代码:

<ItemsControl ItemsSource="{Binding Items}" Grid.IsSharedSizeScope="True"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
       <Grid Visibility="{Binding ElementName=toggleButton, Path=IsChecked, Converter={StaticResource BoolToVisConverter}}" > 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto" SharedSizeGroup="nameColumn"/> 
        <ColumnDefinition Width="Auto"/> 
        <ColumnDefinition Width="*" /> 
       </Grid.ColumnDefinitions> 
       <Border Grid.Column="0" Style="{StaticResource BodyPropertyGrid_CellBorder}"> 
        <TextBlock Text="{Binding Path=Name}"/> 
       </Border> 
       <GridSplitter Grid.Column="1" Width="2" 
           ResizeBehavior="PreviousAndNext" 
           Style="{StaticResource BodyPropertyGridSplitter}"/> 
       <Border Grid.Column="2" Style="{StaticResource BodyPropertyGrid_CellBorder}"> 
        <ContentControl Content="{Binding}" 
            ContentTemplateSelector="{StaticResource propertyItemTemplateSelector}"/> 
       </Border> 
      </Grid> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
0

可惜你没有为我们提供了一个很好的一段简单的代码,只有证明你的问题,我没有足够的时间来得到它来编译和在我的测试项目中运行,所以我只能给你建议和未经测试的解决方下一次,请花时间展示一个代码示例,我们可以将其复制并粘贴到项目中。

你也许能够得到你的“捉襟见肘” GridSplitter如果你加入所有的行使用Grid.IsSharedSizeScope Attached PropertyGrid S:

<Grid Visibility="{Binding ElementName=toggleButton, Path=IsChecked, Converter= 
    {StaticResource BoolToVisConverter}}" Grid.IsSharedSizeScope="True"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*" SharedSizeGroup="FirstColumn" /> 
     <ColumnDefinition Width="Auto" SharedSizeGroup="GridSplitterColumn" /> 
     <ColumnDefinition Width="*" SharedSizeGroup="LastColumn" /> 
    </Grid.ColumnDefinitions> 
    ... 
</Grid> 
+0

感谢您的快速回答。不幸的是它没有奏效。 GridSplitter不能再被移动,并且列具有自动宽度。对不起,以前没有添加测试代码。我编辑了我的问题并添加了制作测试项目所需的所有代码。 – Martijn

相关问题