2008-10-01 9 views
8

Windows Forms pozwala na tworzenie Komponentów, elementów niewizualnych, które mogą mieć projektanta. Wbudowane komponenty obejmują BackgroundWorker, Timer i wiele obiektów ADO .NET. Jest to dobry sposób na łatwą konfigurację skomplikowanego obiektu i umożliwia on wiązanie danych przy pomocy projektanta.Jaki jest ekwiwalent WPF dla komponentów WinForms?

Szukałem w WPF, a nie wydaje się jak jest jakaś koncepcja komponentów. Czy mam rację co do tego? Czy istnieje jakiś sposób tworzenia komponentów (lub czegoś podobnego do komponentu), które przeoczyłem?

Mam akceptowane odpowiedź Boba bo po wielu badaniach czuję się fantazyjne Adorners są prawdopodobnie jedynym sposobem, aby to zrobić.

Odpowiedz

5

Wygląda na to, że Microsoft stara się odejść od posiadania komponentów i podobnych rzeczy w GUI. Myślę, że WPF stara się ograniczyć większość tego, co jest w XAML, do stricte GUI. Powiązanie danych wydaje mi się jedynym wyjątkiem. Wiem, że staram się zachować wszystko inne w kodzie z tyłu lub w oddzielnych klasach lub zjazdach.

Prawdopodobnie nie jest to odpowiednia odpowiedź, ale moja 0,02 USD.

1

Jak dotąd, jedynym podejściem widzę, że sens jest stworzenie instancji klasy zasobu statyczne i skonfigurować go od XAML. To działa, ale byłoby miło, gdyby było coś takiego jak taca komponentów projektanta WinForm, w której mogłyby one mieszkać.

1

można umieścić cokolwiek chcesz wewnątrz słownika zasobów, w tym klas, które nie mają związku, co tak zawsze do WPF.

Następujący XAML dodaje ciąg "Hello" bezpośrednio do okna (rzeczywisty ciąg znaków, a nie kontrolka, która pokazuje ciąg znaków), możesz użyć tej samej metody do umieszczenia czegokolwiek - w tym klas, które sam napiszesz do pliku 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> 
1

Mam to samo pytanie. Zaletą mechanizmu podobnego do komponentu jest to, że projektant może dodać go do Blend, skonfigurować w projektancie za pomocą edytora właściwości i użyć powiązania danych. Co sądzisz o poniższym rozwiązaniu? To działa.

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 
} 

I jest używany w następujący sposób.

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