2017-08-18 5 views
0

Hinzufügen von Sammlungen von Schaltflächen in meinem Benutzersteuerelement (Optionen). In Xaml Disigner werden die angezeigt.Wpf-Bindungssammlungseigenschaft in UserControl (XAML)

Output Wenn ich meine Anwendung ausführen:

  • Wenn Optionen nicht initialisiert, dann wird ein Fehler XamlObjectWriterException: Property Collection "WpfAppUserControl.Buttons" "Optionen" (null)..
  • Wenn Options = new List(), dann window without buttons

MainWindow.xaml

<Window x:Class="WpfAppUserControl.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfAppUserControl" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="250" Width="300"> 
    <Grid> 
     <local:Buttons x:Name="Buttons" 
         VerticalAlignment="Center" 
         HorizontalAlignment="Center" 
         HorizontalContentAlignment="Center"> 
      <local:Buttons.Options> 
       <Button Content="Agudabi 1" Height="20" Margin="2" /> 
       <Button Content="Agudabi 2" Height="20" Margin="2" /> 
       <Button Content="Agudabi 3" Height="20" Margin="2" /> 
      </local:Buttons.Options> 
     </local:Buttons> 
    </Grid> 
</Window> 

Buttons.xaml

<UserControl x:Class="WpfAppUserControl.Buttons" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:WpfAppUserControl" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <WrapPanel x:Name="InternalContainer" Orientation="Horizontal" HorizontalAlignment="Center"/> 
    </Grid> 
</UserControl> 

Buttons.xaml.cs

#region Usings 

using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Controls; 

#endregion 

namespace WpfAppUserControl 
{ 
    public partial class Buttons : UserControl 
    { 
     public Buttons() 
     { 
      //Options = new ObservableCollection<Button>(); 
      InitializeComponent(); 
     } 

     public ObservableCollection<Button> Options 
     { 
      get { return (ObservableCollection<Button>) GetValue(OptionsProperty); } 
      set { SetValue(OptionsProperty, value); } 
     } 

     public static readonly DependencyProperty OptionsProperty = 
      DependencyProperty.Register(nameof(Options), typeof(ObservableCollection<Button>), typeof(Buttons), 
             new PropertyMetadata(/*new ObservableCollection<Button>()*/, PropertyChangedCallback)); 

     private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var obj = d as Buttons; 

      foreach (var button in obj.Options) 
      { 
       obj.InternalContainer.Children.Add(button); 
      } 
     } 
    } 
} 

Antwort

0

erste OptionsProperty mit einem leeren ObservableCollection initialisieren:

public partial class Buttons : UserControl 
{ 
    public Buttons() 
    { 
     Options = new ObservableCollection<Button>(); 

     InitializeComponent(); 
    } 

    public ObservableCollection<Button> Options 
    { 
     get { return (ObservableCollection<Button>) GetValue(OptionsProperty); } 
     set { SetValue(OptionsProperty, value); } 
    } 

    public static readonly DependencyProperty OptionsProperty = 
     DependencyProperty.Register("Options", typeof(ObservableCollection<Button>), typeof(Buttons));  
} 

Clemens kommentierte, dass "nie den Standardwert einer Sammlung Typ eingestellt DP auf etwas anderes als null. Andernfalls werden alle Instanzen der UserControl-Klasse auf derselben Standardauflistungsinstanz ausgeführt. "Das gleiche gilt für jeden Referenztyp. So erfolgt die Eigenschaftsinitialisierung im Konstruktor.

Sie können ohne PropertyChangedCallback auskommen, weil es möglich ist, anzuzeigen Sammlung effektiver mit ItemsControl:

<UserControl x:Name="myUC" x:Class="WpfAppUserControl.Buttons" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:WpfAppUserControl" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
    <ItemsControl ItemsSource="{Binding Path=Options, ElementName=myUC}"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel x:Name="InternalContainer" Orientation="Horizontal" HorizontalAlignment="Center"/> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
    </ItemsControl> 
    </Grid> 
</UserControl> 

beachten Sie, dass PropertyChangedCallback nicht ausgelöst, wenn Sie Elemente zu einer Sammlung hinzugefügt werden, da Sammlung Immobilie selbst nicht geändert hat, ist es die gleiche Referenz

+1

* Niemals * den Standardwert einer Abhängigkeitseigenschaft des Auflistungstyps auf etwas anderes als 'null' setzen. Andernfalls werden alle Instanzen der UserControl-Klasse für die gleiche standardmäßige Auflistungsinstanz ausgeführt. – Clemens

+0

@Clemens, danke für Ihren rechtzeitigen Vorschlag. Ich habe die Konsequenzen der Verwendung der Referenztypinstanz nicht vollständig erkannt. Fest.Ich werde es hier behalten, weil jemand in derselben Straßensperre laufen könnte. Ich bin nur froh, dass ich es in einer Sandbox-Umgebung gelernt habe :) – ASh

1

Hier ist ein Beispiel dafür, was Sie sho Machst du eigentlich.

Statt eines Usercontrol mit einer Sammlung Eigenschaft, verwenden Sie ein Items wie folgt aus:

public class ViewModel 
{ 
    public ObservableCollection<Option> Options { get; } 
     = new ObservableCollection<Option>(); 
} 

public class Option 
{ 
    public string Name { get; set; } 
    public ICommand Command { get; set; } 
} 
:

<ItemsControl ItemsSource="{Binding Options}"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <WrapPanel/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Button Content="{Binding Name}" Command="{Binding Command}" 
        Height="20" Margin="2"/> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Dann mit einer Sammlung von Datenelementen mit Eigenschaften für die Schaltfläche Inhalt und Befehl ein Ansichtsmodell erstellen

Initialisieren Sie es wie unten gezeigt, wo die ICommand-Implementierung der Kürze halber weggelassen wird. Durchsuchen Sie das Web nach RelayCommand, um Details zur Implementierung zu erhalten.

public MainWindow() 
{ 
    InitializeComponent(); 

    var vm = new ViewModel(); 
    vm.Options.Add(new Option { Name = "Agudabi 1" }); 
    vm.Options.Add(new Option { Name = "Agudabi 2" }); 
    vm.Options.Add(new Option { Name = "Agudabi 3" }); 

    DataContext = vm; 
} 
Verwandte Themen