Riktlinjer för att utforma stilabla kontroller
I det här dokumentet sammanfattas en uppsättning metodtips att tänka på när du utformar en kontroll som du vill ska vara lätt att stilisera och templatable. Vi kom till den här uppsättningen metodtips genom mycket utvärdering och fel när vi arbetade med temakontrollformaten för den inbyggda WPF-kontrolluppsättningen. Vi har lärt oss att lyckad formatering är lika mycket en funktion av en väldesignad objektmodell som den är av själva stilen. Den avsedda målgruppen för det här dokumentet är kontrollförfattaren, inte formatförfattaren.
Terminologi
"Formatering och mallning" refererar till den uppsättning tekniker som gör det möjligt för en kontrollförfattare att skjuta upp kontrollens visuella aspekter till kontrollens format och mall. Den här sviten med tekniker omfattar:
Stilar (inklusive egenskapsinställningar, utlösare och storyboards).
Resurser.
Kontrollmallar.
Datamallar.
En introduktion till formatering och templatering finns i Styling och Templating.
Innan du börjar: Förstå din kontroll
Innan du går in på dessa riktlinjer är det viktigt att du förstår och har definierat den gemensamma användningen av din kontroll. Styling exponerar en ofta oordnad uppsättning möjligheter. Kontroller som skrivs för att användas brett (i många program, av många utvecklare) står inför utmaningen att formatering kan användas för att göra långtgående ändringar i kontrollens visuella utseende. Den formaterade kontrollen kanske inte ens liknar vad skaparen av kontrollen avsett. Eftersom flexibiliteten som erbjuds av styling i stort sett är gränslös kan du använda idén om vanlig användning för att hjälpa dig att avgränsa dina beslut.
För att förstå kontrollens vanliga användning är det bra att tänka på kontrollens värdeförslag. Vad ger din kontroll till bordet som ingen annan kontroll kan erbjuda? Vanlig användning innebär inte något specifikt visuellt utseende, utan snarare kontrollens filosofi och en rimlig uppsättning förväntningar på dess användning. Med den här förståelsen kan du göra vissa antaganden om kompositionsmodellen och de stildefinierade beteendena för kontrollen i det vanliga fallet. När det gäller ComboBoxger till exempel inte förståelse för den vanliga användningen dig någon insikt om huruvida en viss ComboBox har rundade hörn, men det ger dig insikt i att ComboBox förmodligen behöver ett popup-fönster och något sätt att växla huruvida det är öppet.
Allmänna riktlinjer
Tillämpa inte mallkontrakt strikt. Mallkontraktet för en kontroll kan bestå av element, kommandon, bindningar, utlösare eller till och med egenskapsinställningar som krävs eller förväntas för att en kontroll ska fungera korrekt.
Minimera kontrakt så mycket som möjligt.
Designa runt förväntan att under designtiden (det vill säga när du använder ett designverktyg) är det vanligt att en kontrollmall är i ett ofullständigt tillstånd. WPF erbjuder inte en "sammansatt" tillståndsinfrastruktur, så kontroller måste skapas med förväntningen att ett sådant tillstånd kan vara giltigt.
Utlös inte undantag när någon aspekt av ett mallkontrakt inte följs. I detta sammanhang bör paneler inte utlösa undantag om de har för många eller för få barn.
Dela in kringutrustningsfunktioner i mallhjälpelement. Varje kontroll bör fokusera på dess kärnfunktioner och verkliga värdeförslag och definieras av kontrollens gemensamma användning. Använd därför sammansättnings- och hjälpelement i mallen för att aktivera kringutrustningsbeteenden och visualiseringar, dvs. de beteenden och visualiseringar som inte bidrar till kontrollens kärnfunktioner. Hjälpelementen delas in i tre kategorier:
fristående hjälptyper är offentliga och återanvändbara kontroller eller primitiver som används "anonymt" i en mall, vilket innebär att varken hjälpelementet eller den formaterade kontrollen känner till den andra. Tekniskt sett kan alla element vara en anonym typ, men i det här sammanhanget beskriver termen de typer som kapslar in specialiserade funktioner för att aktivera målscenarier.
Typbaserade hjälpelement är en ny typ av element som kapslar in specialiserad funktionalitet. Dessa element är vanligtvis utformade med ett smalare utbud av funktioner än vanliga kontroller eller primitiver. Till skillnad från fristående hjälpelement är typbaserade hjälpelement medvetna om kontexten där de används och måste vanligtvis dela data med kontrollen till vars mall de tillhör.
Namngivna hjälpelement är vanliga kontroller eller grundläggande element som en kontroll förväntar sig ska finnas i dess mall. Dessa element får ett välkänt namn i mallen, vilket gör det möjligt för en kontroll att hitta elementet och interagera med det programmatiskt. Det kan bara finnas ett element med ett förnamn i en mall.
I följande tabell visas hjälpelement som används av kontrollformat i dag (den här listan är inte fullständig):
Element Typ Används av ContentPresenter Typbaserad Button, CheckBox, RadioButton, Frameoch så vidare (alla ContentControl typer) ItemsPresenter Typbaserad ListBox, ComboBox, Menuoch så vidare (alla ItemsControl typer) ToolBarOverflowPanel Heter ToolBar Popup Fristående ComboBox, ToolBar, Menu, ToolTipoch så vidare RepeatButton Heter Slider, ScrollBaroch så vidare ScrollBar Heter ScrollViewer ScrollViewer Fristående ListBox, ComboBox, Menu, Frameoch så vidare TabPanel Fristående TabControl TextBox Heter ComboBox TickBar Typbaserad Slider Minimera obligatoriska användardefinierade bindningar eller egenskapsinställningar för hjälpelement. Det är vanligt att ett hjälpelement kräver vissa bindningar eller egenskapsinställningar för att fungera korrekt i kontrollmallen. Hjälpelementet och den mallade kontrollen bör så mycket som möjligt upprätta dessa inställningar. När du anger egenskaper eller upprättar bindningar bör du vara noga med att inte åsidosätta värden som angetts av användaren. Specifika metodtips är följande:
Namngivna hjälpelement bör identifieras av den överordnade och den överordnade ska upprätta nödvändiga inställningar för hjälpelementet.
Typbaserade hjälpelement bör upprätta nödvändiga inställningar direkt på sig själva. Detta kan kräva att hjälpelementet frågar efter informationskontexten där det används, inklusive dess
TemplatedParent
(kontrolltypen för mallen där den används). Till exempel binder ContentPresenter automatiskt egenskapenContent
för dessTemplatedParent
till egenskapen Content när den används i en ContentControl härledd typ.Fristående hjälpelement kan inte optimeras på det här sättet eftersom varken hjälpelementet eller det överordnade elementet känner till det andra per definition.
Använd egenskapen Namn för att flagga element i en mall. En kontroll som behöver hitta ett element i sin stil för att få åtkomst till det programmatiskt bör göra det med hjälp av egenskapen
Name
ochFindName
paradigm. En kontroll bör inte utlösa ett undantag när ett element inte hittas, men tyst och smidigt inaktivera de funktioner som krävde det elementet.Använd bästa praxis för att uttrycka kontrolltillstånd och beteende i en stil. Följande är en ordnad lista över bästa praxis för att uttrycka ändringar av och beteende hos kontrolltillstånd i en stil. Du bör använda det första objektet i listan som aktiverar ditt scenario.
Egenskapsbindning. Exempel: bindning mellan ComboBox.IsDropDownOpen och ToggleButton.IsChecked.
Utlösta egenskapsändringar eller egenskapsanimeringar. Exempel: hovringstillståndet för en Button.
Befallning. Exempel: LineUpCommand / LineDownCommand i ScrollBar.
Fristående hjälpelement. Exempel: TabPanel i TabControl.
Typbaserade hjälptyper. Exempel: ContentPresenter i Button, TickBar i Slider.
Bubblade händelser från namngivna hjälptyper. Om du lyssnar efter bubblade händelser från ett formatelement måste du kräva att elementet som genererar händelsen kan identifieras unikt. Exempel: Thumb i ToolBar.
Anpassat
OnRender
beteende. Exempel: ButtonChrome i Button.
Använd stilutlösare (till skillnad från malltriggers) sparsamt. Utlösare som påverkar egenskaper för element i mallen måste deklareras i mallen. Utlösare som påverkar egenskaperna för kontrollen (ingen
TargetName
) kan deklareras i formatet om du inte vet att en ändring av mallen också ska förstöra utlösaren.Var konsekvent med befintliga formatmönster. Många gånger finns det flera sätt att lösa ett problem. Var medveten om och, när det är möjligt, konsekvent med befintliga kontrollstilmönster. Detta är särskilt viktigt för kontroller som härleds från samma bastyp (till exempel ContentControl, ItemsControl, RangeBaseoch så vidare).
Exponera egenskaper för att aktivera vanliga anpassningsscenarier utan att ändra. WPF stöder inte pluggbara/anpassningsbara delar, så en kontrollanvändare har bara två anpassningsmetoder: ange egenskaper direkt eller ange egenskaper med hjälp av formatmallar. Med detta i åtanke är det lämpligt att visa upp ett begränsat antal egenskaper som är inriktade på mycket vanliga anpassningsscenarier med hög prioritet som annars skulle kräva omförsök. Här följer metodtips för när och hur du aktiverar anpassningsscenarier:
Mycket vanliga anpassningar bör exponeras som egenskaper för kontrollen och förbrukas av mallen.
Mindre vanliga (men inte sällsynta) anpassningar bör exponeras som bifogade egenskaper och användas av mallen.
Det är acceptabelt att kända men sällsynta anpassningar kräver ommodellering.
Temaöverväganden
Temaformat bör försöka ha konsekvent egenskapssemantik i alla teman, men garantera inte. Som en del av dokumentationen bör kontrollen ha ett dokument som beskriver kontrollens egenskapssemantik, det vill säga "innebörden" av en egenskap för en kontroll. Till exempel bör ComboBox-kontrollen definiera innebörden av egenskapen Background i ComboBox. De standardstilar som används för din kontroll bör försöka följa den semantiken som definieras i dokumentet för alla teman. Kontrollanvändare bör å andra sidan vara medvetna om att egenskapssemantik kan ändras från tema till tema. I vissa fall kanske en viss egenskap inte är uttrycksbar enligt de visuella begränsningar som krävs av ett visst tema. (Det klassiska temat har till exempel inte en enda ram där
Thickness
kan användas på många kontroller.)Temaformat behöver inte ha konsekvent utlösarsemantik för alla teman. Beteendet som exponeras av ett kontrollformat via utlösare eller animeringar kan variera från tema till tema. Kontrollanvändare bör vara medvetna om att en kontroll inte nödvändigtvis använder samma mekanism för att uppnå ett visst beteende i alla teman. Ett tema kan till exempel använda en animering för att uttrycka hovringsbeteende där ett annat tema använder en utlösare. Detta kan leda till inkonsekvenser i beteendebevarande på anpassade kontroller. (Om du till exempel ändrar bakgrundsegenskapen kanske det inte påverkar kontrollens hovringstillstånd om det tillståndet uttrycks med hjälp av en utlösare. Men om hovringstillståndet implementeras med hjälp av en animering kan det irreparabelt bryta animeringen och därmed tillståndsövergången om du ändrar till bakgrund.)
Temaformat behöver inte ha konsekvent "layout"-semantik i alla teman. Standardformatet behöver till exempel inte garantera att en kontroll upptar samma storlek i alla teman eller garantera att en kontroll har samma innehållsmarginaler/utfyllnad i alla teman.
Se även
- Stilsättning och mallhantering
- översikt över kontrollredigering
.NET Desktop feedback