1

I had a question some time ago (this is NO duplicate) as you can see here: WPF Simple DataMatrix. I asked about creating a matrix of LED lights on screen. I used to that the marked answer and created the matrix. It is displayed very well and I also applied commands on the Ellipse so I can edit the Matrix but also that works without any lag.

As result this is my code for the Matrix:

<ItemsControl x:Class="HTLED.WPF.Controls.LedGrid"
         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:Data="clr-namespace:HTLED.Data;assembly=HTLED.Data"
         xmlns:Controls="clr-namespace:HTLED.WPF.Controls"
         xmlns:Commands="clr-namespace:HTLED.Client.Commands;assembly=HTLED.Client"
         xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
         xmlns:ViewModel="clr-namespace:HTLED.Client.ViewModel;assembly=HTLED.Client"
         mc:Ignorable="d"
         d:DataContext="{d:DesignInstance ViewModel:LedContainerViewModel}" Name="ledGridRoot" >
<ItemsControl.Resources>
    <DataTemplate x:Key="ledTemplate" DataType="{x:Type Data:Led}">
        <Ellipse Name="ellipse" Fill="Green" Stretch="Uniform" SnapsToDevicePixels="True">
            <Interactivity:Interaction.Triggers>
                <Interactivity:EventTrigger EventName="PreviewMouseMove">
                    <Commands:CommandTrigger Command="{Binding ElementName=ledGridRoot, Path=DataContext.LedGridViewModel.LedMouseMoveCommand}" PassEventArgsToCommand="True"/>
                </Interactivity:EventTrigger>
                <Interactivity:EventTrigger EventName="PreviewMouseLeftButtonDown">
                    <Commands:CommandTrigger Command="{Binding ElementName=ledGridRoot, Path=DataContext.LedGridViewModel.LedOnCommand}" PassEventArgsToCommand="True"/>
                </Interactivity:EventTrigger>
                <Interactivity:EventTrigger EventName="PreviewMouseRightButtonDown">
                    <Commands:CommandTrigger Command="{Binding ElementName=ledGridRoot, Path=DataContext.LedGridViewModel.LedOffCommand}" PassEventArgsToCommand="True"/>
                </Interactivity:EventTrigger>
            </Interactivity:Interaction.Triggers>
        </Ellipse>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=State}" Value="Off">
                <Setter TargetName="ellipse" Property="Fill" Value="Red"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource ledTemplate}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Controls:StretchStackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

In the background I have a class called LedMatrix. It has a property with the collection of the leds:

    ObservableCollection<ObservableCollection<Led>> _leds;
    public ObservableCollection<ObservableCollection<Led>> Leds
    {
        get { return _leds ?? (_leds = CreateMatrix(XSize, YSize)); }
        set { SetProperty(value, ref _leds, () => Leds); }
    }

The matrix is contained by another control:

<Canvas x:Class="HTLED.WPF.Controls.LedContainer"
         ....
         mc:Ignorable="d" 
         d:DataContext="{d:DesignInstance ViewModel:LedContainerViewModel}"
         d:DesignHeight="300" d:DesignWidth="300" Name="layoutRoot" Drawing:DrawingCore.EnableDrawing="True">
<Viewbox Canvas.Top="0" Canvas.Left="0" Width="{Binding ElementName=layoutRoot, Path=ActualWidth}"
         Height="{Binding ElementName=layoutRoot, Path=ActualHeight}">
    <Grid>
        <Controls:LedGrid Width="50000" Height="25000" Margin="500" DataContext="{Binding Path=Main.LedContainerViewModel}" ItemsSource="{Binding Path=LedContentContainer.Content}" />
    </Grid>
</Viewbox>

As you can see I set the ItemsSource of the Matrix in the container. That Itemssource Is a Interface like this:

public interface ILedContentContainer
{
    LedMatrix Content { get; set; }
}

And the LedMatrix I already showed before (the ObservableCollection<ObservableCollection<Led>>).

And now the very important: I have the change the LedMatrix (the Itemssource of LedGrid - see LedGridContainer) very often because it is some kind of an animation. The problem is that that all is very very slow. So I wanted to ask if you know some optimations?

Again I have to change the LedMatrix very very fast.

Community
  • 1
  • 1
Florian
  • 5,918
  • 3
  • 47
  • 86

1 Answers1

0

If you apply a whole new ObservableCollection each time as Led changes, the complete grid has to be rendered again and again. You should change the State property of the Led's that are changing (they should fire PropertyChanged).

Also, if the amount of Led's is constant, you don't need an ObservableCollection at all. You can use any IEnumerable.

DanielB
  • 19,910
  • 2
  • 44
  • 50
  • Ok I just also found out that I just have to sync the state and the performance gets huge. But the thing with ObservableCollection... The amount of leds ist constant so I don t have to use one ... you are right but is does a observablecollection takes performance? – Florian Aug 16 '12 at 15:21
  • Yeah, you don't need it. The advantage of an ObservableColletion is, that an item is removed, added or moved in order, the bound ItemControl renders the modified items again. But in your case, only a property of an item within the collection changes, so this feature isn't used. It may cost performance while filling the collection, later on I don't think. – DanielB Aug 16 '12 at 15:23