2011-01-28 6 views
3

Я создаю нечто похожее на PropertyGrid, где я хочу показать свойства объектов. По специальным причинам я не буду использовать PropertyGrid, но создаю свой собственный.WPF - UserControls очень медленно

Для каждого свойства я создал настраиваемый пользовательский контроль. Теперь, к моему ужасу, представление очень плохое. Если у меня есть что-то вроде 100 свойств, для отображения их в StackPanel/Listbox требуется 500 миллисекунд.

Я сделал эксперимент, в котором я добавляю 200 стандартных UserControls в StackPanel. Это заняло около 50 миллисекунд. По-прежнему очень большое число, я думаю.

Должен ли я использовать пользовательские элементы управления для такой цели? Кажется очень объектно-ориентированным, чтобы сделать это таким образом, и я не могу увидеть другое решение.

Однако я вижу, что PropertyGrid и TreeView отлично работают, так что они сделали и что мне делать?

Edit:

 Stopwatch stopwatch = new Stopwatch(); 
     stopwatch.Start(); 
     using (var suspend = Dispatcher.DisableProcessing()) 
     { 
      // Add all children here 
      for (int i = 0; i < 200; i++) 
      { 
       this.propertiesStackPanel.Children.Add(new System.Windows.Controls.Button(){Content = "Testing"}); 
      } 
     } 
     stopwatch.Stop(); 

Это все еще занимает около 50 миллисекунд. Если я перейду на свой собственный пользовательский контроль, он будет намного выше. Я мог бы добавить, что прокрутка не проблема.

Edit2:

OK. Это не имеет никакого отношения к stackpanel. Я узнал, что это потому, что создание UserControls - очень дорогостоящая операция. Если у вас есть какие-либо другие идеи о том, что делать, я бы с удовольствием послушает их :)

EDIT3: Ничего не происходит в конструкторе моего UserControl, кроме метода InitializeComponent. Ниже приведен пример пользовательского контроля, который я добавляю.

<UserControl 
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" 
mc:Ignorable="d" 
x:Class="PropertyBox.GroupUC" 
x:Name="UserControl" 
d:DesignWidth="640" d:DesignHeight="480" Background="#FF32B595" BorderThickness="0"> 

<Grid x:Name="LayoutRoot"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="20px"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 
    <Border x:Name="border" BorderThickness="0,1" Grid.Column="1"> 
     <TextBox Text="TextBox" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Right" BorderThickness="0" Padding="0" Visibility="Hidden"/> 
    </Border> 
    <Label x:Name="groupNameLabel" HorizontalAlignment="Left" Margin="5,0,0,0" VerticalAlignment="Center" Content="Label" Padding="0" Grid.Column="1"/> 
    <Button x:Name="expandButton" HorizontalAlignment="Left" VerticalAlignment="Center" Width="12" Height="12" Content="" Click="ExpandButtonClick" Margin="4,0,0,0" Padding="0" Grid.ColumnSpan="2" d:IsHidden="True"/> 
    <Image x:Name="expandButton2" Visibility="Hidden" Width="12" Height="12" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None"/> 
</Grid> 

+0

привет чувак. У меня схожая проблема. Рендеринг был быстрым, но создание PAINFULLY медленно. Еще не найдено ни одного решения – GorillaApe

ответ

5

Я подозреваю, что вы вызывая много обновлений макета, добавляя свои сотни детей.

Если это узкое место, вы можете рассмотреть возможность:

using(var suspend = Dispatcher.DisableProcessing()) 
{ 
     // Add all children here 
} 

Это приведет к диспетчеру прекратить обработку сообщений при добавлении элементов управления, и сделать весь макет и сделать за один проход на конец.

+1

Выглядит многообещающе! Ответит в течение следующих 24 часов, когда у меня была возможность проверить его и сообщить вам результат. –

+1

Просто попробовал. Не имеет значения :( –

+0

@bobjink: Интересно - ваш UserControl выполняет работу в своем конструкторе? Можете ли вы опубликовать код, показывающий, что вы делаете во время строительства/добавления? –

1

Если вы обнаружите, что создание большого количества UserControl s является слишком дорогостоящей операцией, как насчет решения, в котором вам не нужно создавать UserControl?

Я отнюдь не эксперт WPF, но как насчет использования привязки данных ListBox или ListView к списку объектов, каждый из которых представляет одно свойство объекта, находящегося под контролем? Вместо StackPanel у вас будет Listbox или ListView; вместо UserControl s, вы бы определили один или несколько DataTemplate s.


Базовый пример кода:

Определить тип, представляющий собой запись в пользовательской таблице свойств; например:

public namespace YourApplication 
{ 
    public class Prop 
    { 
     public string Name { get; set; } 
     public Type Type { get; set; } 
    } 

    public class Props : List<Prop> { } 
} 

Затем в XAML (я не могу в настоящее время проверить это на 100% правильность, но, надеюсь, вы получите идею):

<Window ... xmlns:local="clr-namespace:YourApplication"> 
    <Window.Resources> 
    <!-- this Prop list serves only as a demonstration in the XAML designer --> 
    <local:Props x:Key="somePropsForDemonstration"> 
     <local:Prop Name="Name" Type="System.String" /> 
     <local:Prop Name="Age" Type="System.TimeSpan" /> 
    </local:Props> 
    </Window.Resources> 
    <!-- here's your StackPanel replacement; bind it to a real items source --> 
    <ListView ItemsSource={StaticResource somePropsForDemonstration}> 
    <ListView.ItemsTemplate> 
     <!-- this is a UI template that defines how a Prop object gets displayed; 
      together with the Prop type, it replaces your UserControl --> 
     <DataTemplate DataType="local:Prop"> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="{Binding Name}" FontWeight="Bold" /> 
      <TextBlock Text=": " /> 
      <TextBlock Text="{Binding Type}" FontStyle="Italic" /> 
     </StackPanel> 
     </DataTemplate> 
    </ListView.ItemsTemplate> 
    </ListView> 
</Window> 

Я, кажется, помню, что есть способы иметь «полиморфные» шаблоны данных; то есть. в зависимости от типа объекта, вы можете использовать другой подкласс класса Prop, а также использовать другой шаблон данных для каждого типа элемента.

+0

Это возможность Я сам не эксперт WPF/xaml, поэтому я стараюсь избегать писать как можно больше xaml. Сейчас я использую материал GUI в коде для каждого пользователя, поэтому, если я последую вашему предложению, мне придется реализовать это как xaml, если я использую datatemplates. Я думаю, есть хороший шанс, что ваше решение будет работать, хотя это может быть решением :) –

Смежные вопросы