2009-04-27 1 views
12

Dove posso trovare informazioni sufficienti su come i pennelli funzionano per implementare il mio System.Windows.Media.Brush? Sono in grado di gestire tutto il bagaglio congelato, ma non è proprio ovvio ciò di cui ho bisogno per farlo funzionare.Come si implementa un pennello personalizzato in WPF?


Sì, così non volevo dire che io voglio usare un pennello predefinito. Voglio estendere System.Windows.Media.Brush, che è una classe astratta. Questo è tutto puramente per la mia edificazione. Non sono nemmeno sicuro di che tipo di pennello potrei fare. Stavo solo cercando di imparare come funzionano i pennelli. Come in:

public AwesomeBrush : Brush 
{ 

    protected override Freezable CreateInstanceCore() 
    { 
     return new AwesomeBrush(); 
    } 

    ... // concrete brush stuff 

} 
+0

Potrebbe essere utile fornire ulteriori informazioni su ciò che si sta tentando di fare. Non sono sicuro di cosa creerebbe un pennello, ma ecco una buona lista dei molti pennelli incorporati in wpf: http://msdn.microsoft.com/en-us/library/aa970904.aspx –

risposta

3

Non si può fare un pennello WPF personalizzato che eredita dalla classe System.Windows.Media.Brush, perché quella classe contiene membri astratti che sono interni.

Se si utilizza Reflector per visualizzare il codice sorgente di System.Windows.Media.Brush classe, si vedranno i seguenti metodi astratti interne:

internal abstract DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel); 
internal abstract DUCE.Channel GetChannelCore(int index); 
internal abstract int GetChannelCountCore(); 
internal abstract DUCE.ResourceHandle GetHandleCore(DUCE.Channel channel); 
internal abstract void ReleaseOnChannelCore(DUCE.Channel channel); 

Questi devono essere sostituiti, ma non può essere perché sono interne.

Nota: modificato la mia risposta, perché risposta precedente era di circa System.Drawing.Brush e irrilevante a questa domanda. Un ringraziamento speciale a Mikko Rantanen per il suo commento.

+4

Puoi ereditare dalla classe Brush - come hai detto tu, le classi astratte e astratte DEVONO essere ereditate. –

+0

Di cosa si tratta Brush che lo rende impossibile da ereditare? So che tutte le implementazioni sono sigillate, ma dovremmo essere in grado di derivare da Brush, giusto? – MojoFilter

+1

Accidenti ai costruttori interni! Sono stato sventato da te prima! – MojoFilter

9

Ho dato una rapida occhiata ai pennelli esistenti usando lo Reflector. Sembra che la loro implementazione sia piuttosto chiusa e dipende da molti impianti idraulici internal. Mentre potrebbe essere possibile implementare il proprio pennello, sembra che non sia un'opzione supportata. Potrebbe anche essere che i controlli WPF siano strettamente legati ai pennelli esistenti e non funzionino con uno personalizzato.

Molto probabilmente il modo migliore per ottenere qualcosa che assomiglia a pennelli personalizzati è utilizzare lo DrawingBrush con una logica di disegno complessa. Puoi comporre il pennello da disegno da forme complesse usando altri pennelli in modo che questo ti consenta di raggiungere l'obiettivo richiesto.

Aggiornamento dopo modifica

come questo è per l'educazione, si potrebbe essere migliore fuori scaricando il riflettore e l'utilizzo che per vedere come funzionano le spazzole. Non sono pensati per essere auto-implementati e poiché si basano su alcune classi internal a cui i programmatori non hanno accesso normalmente sarà abbastanza difficile farlo.

Anche se ciò che lo rende interessante è che lo Brush documentation ha un'osservazione per gli eredi che guidano nel modo corretto di ereditare dal Pennello.

Ulteriori aggiornamenti

Quando rovistando ho trovato un modo molto pulito per ottenere qualcosa di simile su un chinese blog. Il trucco è usare un'estensione di markup in modo che assomigli ad un pennello. In realtà crea un nuovo pennello immagine basato sui suoi attributi. Sembra che sia giunto alla stessa conclusione che ci sono alcune classi interne che impediscono la facile implementazione.

+0

Sospetto che sia anche così. Non riesco ad immaginare nulla che non possa essere fatto con le implementazioni del pennello fornite nel framework, mi stavo chiedendo se ci potrebbero essere modi divertenti per suddividere tali elementi in modo da renderli davvero chiari per il riutilizzo. – MojoFilter

+0

Aggiunto un aggiornamento che raggiunge qualcosa di simile senza estendere Brush. –

+1

Mi chiedo se la nota nella documentazione del pennello per gli eredi fosse per Microsoft personale e non avrebbe dovuto inserirlo nel documento finale. Quando guardo Reflector, sembra che ci siano molti campi essenziali in Brush e anche GradientBrush sono contrassegnati come interni. Quindi non possiamo raggiungerli. –

3

Ho provato ogni possibile angolazione per una soluzione per creare un pennello personalizzato, dall'utilizzo di MarkupExtensions a fare confusione con gli attributi TypeConverter, poi è passato su di me: basta creare una classe wrapper basata su DependencyObject, creare una DependencyProperty di Type Brush , implementare la personalizzazione, quindi associare a Brush DependencyProperty.

Successivamente, mettere il pennello personalizzato in Risorse

<l:CustomBrush x:Key="CustomBrush" Brush="Magenta" /> 

quindi associare ad esso:

<Line X1="0" Y1="-5" X2="200" Y2="-5" 
     Stroke="{Binding Source={StaticResource CustomBrush}, Path=Brush}" 
     StrokeThickness="12"/> 

penso che questo è meglio che la soluzione MarkupExtension perché non si può mettere uno in risorse e pertanto devi ridefinire le impostazioni personalizzate ogni volta che lo usi.

In ogni caso, questa sembra essere una semplice soluzione per ereditare da qualsiasi oggetto Wpf, e con la flessibilità di Bindings è possibile anche associare i membri dell'oggetto Wpf spostato stesso.

Ecco la semplice classe:

public class CustomBrush : DependencyObject 
{ 
    public CustomBrush() 
    { 
     this.Brush = Brushes.Azure;  
    } 

    #region Brush DependencyProperty 

    [BindableAttribute(true)] 
    public Brush Brush 
    { 
    get { return (Brush)GetValue(BrushProperty); } 
    set { SetValue(BrushProperty, value); } 
    } 
    public static readonly DependencyProperty BrushProperty = 
     DependencyProperty.Register(
     "Brush", 
     typeof(Brush), 
     typeof(CustomBrush), 
     new UIPropertyMetadata(null)); 

    #endregion   
} 
4

di rispondere alla domanda del perché si potrebbe desiderare di avere un pennello personalizzato, prendere in considerazione una geometria complessa e che si desidera riempire con un gradiente che corrisponde alla forma mentre si cambia colori radialmente dal centro della forma (o qualsiasi punto iniziale arbitrario).

Non c'è modo di farlo con un riempimento statico (che elimina praticamente tutti i pennelli esistenti). Non è sufficiente replicare l'oggetto più e più volte e annidarli (e risolvere lo scafo per renderlo tutto a posto), riempiendo ognuno di un colore diverso, l'unico modo pratico è quello di avere un pennello che può guardare l'oggetto che viene riempito .

Questo è effettivamente eseguibile in Moduli.

Ma non sembra che ci sia un modo per farlo in WPF, il che è sfortunato.

In effetti, i pennelli di WPF sono allo stesso tempo sorprendentemente potenti E sorprendentemente limitati. Sono chiaramente progettati per alcuni modelli concettuali, ma non sono affatto sicuro che sia uno di quelli utili oltre a degli effetti visivi piuttosto banali e, come al solito, è stato reso più complesso con strani parametri (scarsamente documentati) che rendono molto semplice, un po 'complicato.