Pregunta

Windows Forms le permite desarrollar componentes, elementos no visuales que puede tener un diseñador. Los componentes incorporados incluyen BackgroundWorker, Timer y muchos objetos ADO .NET. Es una buena manera de proporcionar una configuración fácil de un objeto complicado y permite el enlace de datos asistido por el diseñador.

He estado buscando en WPF, y no parece que haya ningún concepto de componentes. ¿Tengo razón sobre esto? ¿Hay algún método para crear componentes (o algo así como un componente) que haya omitido?

He aceptado la respuesta de Bob porque, después de mucha investigación, siento que los Adorners de fantasía son probablemente la única forma de hacer esto.

¿Fue útil?

Solución

Solo por mis propias observaciones, parece que Microsoft está tratando de dejar de tener componentes y cosas similares en la GUI. Creo que WPF intenta limitar la mayoría de lo que está en el XAML a cosas estrictamente GUI. Enlace de datos supongo que sería la única excepción. Sé que trato de mantener casi todo lo demás en el código subyacente o en clases o conjuntos separados.

Probablemente no sea exactamente la respuesta que querías, pero es mi $ 0.02.

Otros consejos

Tengo la misma pregunta. La ventaja de un mecanismo similar a un componente es que el diseñador puede agregarlo en Blend, configurarlo en el diseñador con el editor de propiedades y usar el enlace de datos. ¿Qué opinas de la solución de abajo? Funciona.

public class TimerComponent : FrameworkElement
{
    public Timer Timer { get; protected set; }

    public TimerComponent()
    {
        if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
        {
            Visibility = Visibility.Collapsed;
            Timer = new Timer(OnTimerTick, null, Timeout.Infinite, Timeout.Infinite);
        }
    }

    void OnTimerTick(object ignore)
    {
        Dispatcher.BeginInvoke(new Action(RaiseTickEvent));
    }

    #region DueTime Dependency Property

    public int DueTime
    {
        get { return (int)GetValue(DueTimeProperty); }
        set { SetValue(DueTimeProperty, value); }
    }

    public static readonly DependencyProperty DueTimeProperty =
        DependencyProperty.Register("DueTime", typeof(int), typeof(TimerComponent), new UIPropertyMetadata(new PropertyChangedCallback(OnDueTimeChanged)));

    static void OnDueTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var target = obj as TimerComponent;
        if (target.Timer != null)
        {
            var newDueTime = (int)e.NewValue;
            target.Timer.Change(newDueTime, target.Period);
        }
    }

    #endregion

    #region Period Dependency Property

    public int Period
    {
        get { return (int)GetValue(PeriodProperty); }
        set { SetValue(PeriodProperty, value); }
    }

    public static readonly DependencyProperty PeriodProperty =
        DependencyProperty.Register("Period", typeof(int), typeof(TimerComponent), new UIPropertyMetadata(new PropertyChangedCallback(OnPeriodChanged)));

    static void OnPeriodChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var target = obj as TimerComponent;
        if (target.Timer != null)
        {
            var newPeriod = (int)e.NewValue;
            target.Timer.Change(target.DueTime, newPeriod);
        }
    }

    #endregion

    #region Tick Routed Event

    public static readonly RoutedEvent TickEvent = EventManager.RegisterRoutedEvent(
        "Tick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TimerComponent));

    public event RoutedEventHandler Tick
    {
        add { AddHandler(TickEvent, value); }
        remove { RemoveHandler(TickEvent, value); }
    }

    private void RaiseTickEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(TimerComponent.TickEvent);
        RaiseEvent(newEventArgs);
    }

    #endregion
}

Y se utiliza de la siguiente manera.

<StackPanel>
    <lib:TimerComponent Period="{Binding ElementName=textBox1, Path=Text}" Tick="OnTimerTick" />
    <TextBox x:Name="textBox1" Text="1000" />
    <Label x:Name="label1" />
</StackPanel>

Hasta ahora, el único enfoque que veo que tiene sentido es hacer de una instancia de la clase un recurso estático y configurarlo desde XAML. Esto funciona, pero sería bueno si hubiera algo como la bandeja de componentes del diseñador WinForms en la que podrían vivir.

Puedes poner lo que quieras dentro de un diccionario de recursos, incluidas las clases que no tienen relación alguna con Wpf.

El siguiente XAML agrega la cadena " Hola " directamente en una ventana (la cadena real, no un control que muestra la cadena), puede usar el mismo método para colocar cualquier cosa, incluidas las clases en las que se escribe en un archivo XAML.

<Window  x:Class="MyApp.Window1"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
<Window.Resources>
    <sys:String x:Key="MyString">Hello</sys:String>
</Window.Resources>
</Window>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top