Optimera prestanda: Databindning
Databindningen för Windows Presentation Foundation (WPF) är ett enkelt och konsekvent sätt för program att presentera och interagera med data. Element kan bindas till data från en mängd olika datakällor i form av CLR objekt och XML.
Det här avsnittet innehåller prestandarekommendationer för databindning.
Så här löses databindningsreferenser
Innan du diskuterar problem med databindningsprestanda är det värt att utforska hur databindningsmotorn för Windows Presentation Foundation (WPF) löser objektreferenser för bindning.
Källan till en WPF-databindning (Windows Presentation Foundation) kan vara valfritt CLR objekt. Du kan binda till egenskaper, underegenskaper eller indexerare för ett CLR objekt. Bindningsreferenserna löses genom att använda antingen Microsoft .NET Frameworks reflection eller en ICustomTypeDescriptor. Här är tre metoder för att lösa objektreferenser för bindning.
Den första metoden handlar om att använda reflektion. I det här fallet används PropertyInfo-objektet för att identifiera egenskapens attribut och ger åtkomst till egenskapsmetadata. När du använder ICustomTypeDescriptor-gränssnittet använder databindningsmotorn det här gränssnittet för att komma åt egenskapsvärdena. Det ICustomTypeDescriptor gränssnittet är särskilt användbart i fall där objektet inte har en statisk uppsättning egenskaper.
Meddelanden om egenskapsändring kan tillhandahållas antingen genom att implementera INotifyPropertyChanged-gränssnittet eller med hjälp av de ändringsmeddelanden som är associerade med TypeDescriptor. Den bästa strategin för att implementera meddelanden om egenskapsändring är dock att använda INotifyPropertyChanged.
Om källobjektet är ett CLR-objekt och källegenskapen är en CLR-egenskap måste databindningsmotorn för Windows Presentation Foundation (WPF) först använda reflektion på källobjektet för att hämta TypeDescriptoroch sedan fråga efter en PropertyDescriptor. Den här sekvensen av reflektionsåtgärder är potentiellt mycket tidskrävande ur ett prestandaperspektiv.
Den andra metoden för att matcha objektreferenser omfattar ett CLR källobjekt som implementerar INotifyPropertyChanged-gränssnittet och en källegenskap som är en CLR egenskap. I det här fallet använder databindningsmotorn reflektion direkt på källtypen och hämtar den nödvändiga egenskapen. Det här är fortfarande inte den optimala metoden, men det kostar mindre i krav för arbetsuppsättningar än den första metoden.
Den tredje metoden för att matcha objektreferenser omfattar ett källobjekt som är en DependencyObject och en källegenskap som är en DependencyProperty. I det här fallet behöver databindningsmotorn inte använda reflektion. I stället löser egenskapsmotorn och databindningsmotorn tillsammans egenskapsreferensen oberoende av varandra. Det här är den optimala metoden för att lösa objektreferenser som används för databindning.
I tabellen nedan jämförs hastigheten för databindningen av egenskapen Text för ett tusen TextBlock element med hjälp av dessa tre metoder.
Binda egenskapen Text för en TextBlock | Bindningstid (ms) | Återgivningstid – innehåller bindning (ms) |
---|---|---|
Till en egenskap för ett CLR objekt | 115 | 314 |
Till en egenskap för ett CLR objekt som implementerar INotifyPropertyChanged | 115 | 305 |
Till en DependencyProperty av en DependencyObject. | 90 | 263 |
Bindning till stora CLR objekt
Det finns en betydande prestandapåverkan när du binder data till ett enda CLR objekt med tusentals egenskaper. Du kan minimera den här effekten genom att dela upp det enskilda objektet i flera CLR objekt med färre egenskaper. Tabellen visar bindnings- och återgivningstiderna för databindning till ett enda stort CLR objekt jämfört med flera mindre objekt.
Databindning 1000 TextBlock-objekt | Bindningstid (ms) | Återgivningstid – innehåller bindning (ms) |
---|---|---|
Till ett CLR objekt med 1 000 egenskaper | 950 | 1200 |
Till 1 000 CLR objekt med en egenskap | 115 | 314 |
Bindning till en ItemsSource
Tänk dig ett scenario där du har ett CLRList<T> objekt som innehåller en lista över anställda som du vill visa i en ListBox. Om du vill skapa en korrespondens mellan dessa två objekt skulle du binda din personallista till egenskapen ItemsSource för ListBox. Anta dock att du har en ny medarbetare som ansluter till din grupp. Du kanske tror att du för att infoga den här nya personen i dina bundna ListBox värden helt enkelt lägger till den här personen i listan över anställda och förväntar dig att den här ändringen identifieras automatiskt av databindningsmotorn. Det antagandet skulle visa sig vara falskt; i själva verket återspeglas inte ändringen i ListBox automatiskt. Det beror på att CLRList<T>-objektet inte automatiskt skapar en händelse som ändrats av samlingen. För att få ListBox att hämta ändringarna måste du återskapa din lista över anställda och koppla den till egenskapen ItemsSource för ListBox. Även om den här lösningen fungerar ger den en enorm prestandapåverkan. Varje gång du omtilldelar ItemsSource av ListBox till ett nytt objekt, kastar ListBox först bort sina tidigare objekt och återskapar hela listan. Prestandaeffekten förstärks om din ListBox kopplas till en komplex DataTemplate.
En mycket effektiv lösning på det här problemet är att förvandla din medarbetarlista till en ObservableCollection<T>. Ett ObservableCollection<T>-objekt skapar ett ändringsmeddelande som databindningsmotorn kan ta emot. Händelsen lägger till eller tar bort ett objekt från en ItemsControl utan att hela listan behöver återskapas.
Tabellen nedan visar den tid det tar att uppdatera ListBox (med virtualisering av användargränssnittet inaktiverad) när ett objekt läggs till. Talet på den första raden representerar den förflutna tiden då det CLRList<T> objektet är bundet till ListBox elementets ItemsSource. Talet på den andra raden representerar den förflutna tiden när en ObservableCollection<T> är bunden till ListBox-elementets ItemsSource. Observera de betydande tidsbesparingarna med hjälp av ObservableCollection<T> databindningsstrategi.
Data som binder ItemsSource- | Uppdateringstid för 1 objekt (ms) |
---|---|
Till ett CLRList<T> objekt | 1656 |
Till en ObservableCollection<T> | 20 |
Binda IList till ItemsControl, inte IEnumerable
Om du har ett val mellan att binda en IList<T> eller en IEnumerable till ett ItemsControl-objekt väljer du det IList<T> objektet. Bindning IEnumerable till en ItemsControl tvingar WPF att skapa ett objekt av typen IList<T>, vilket innebär att prestanda påverkas av onödiga överkostnader för ett extra objekt.
Konvertera inte CLR objekt till XML Just for Data Binding.
MED WPF kan du binda data till XML-innehåll. Databindningen till XML-innehåll är dock långsammare än databindningen till CLR objekt. Konvertera inte CLR objektdata till XML om det enda syftet är databindning.
Se även
.NET Desktop feedback