2017-01-02 3 views
-1

Ich habe einige UserControls innerhalb einer ItemsControl.Artikel von ItemsControl entfernen

Jede UserControl (in meinem Fall JobView genannt) hat eine ContextMenu mit 1 Item ('Entfernen').

Jetzt, wenn das Element auf der UserControls ContextMenuClicked ist, möchte ich es aus der ItemsControlItemCollection entfernen.

Dafür muss ich die Item bekommen, die ContextMenu zugeordnet ist.

Derzeit ich dies mit:

private void Item_Click(object sender, RoutedEventArgs e) 
{ 

    MenuItem item = (MenuItem)sender; 
    JobView view = null; 

    FrameworkElement currentObject = item; 
    while(1 == 1) 
    { 
     currentObject = currentObject.Parent as FrameworkElement; 
     if(currentObject.GetType() == typeof(System.Windows.Controls.Primitives.Popup)) 
     { 
      view = (currentObject as System.Windows.Controls.Primitives.Popup).PlacementTarget as JobView; 
      break; 
     } 
    } 
    //Remove from ObservableCollection<JobView>: 
    JobViews.Remove(view); 
} 

Es funktioniert gut, aber ich bin mir ziemlich sicher, dass es muss mir etwas bessere Lösung.

Ich brauchte ein wenig Zeit, um das herauszufinden, aber ich komme nicht selbst zu einer anderen Lösung.

Wie kann ich die JobView mit dem sender Objekt oder sender völlig falsch in diesem Fall verwendet?

Antwort

1

Das Binden oder Festlegen der ItemsSource eines ItemsControl auf eine ObservableCollection von UIElements oder Views ist falsch. Zumindest, wenn Sie sich für das MVVM-Entwurfsmuster interessieren, welches das empfohlene Muster für alle XAML-basierten Anwendungen ist.

Sie sollten eine Klasse erstellen, die den Zustand Ihrer Jobview und binden an ein ObservableCollection solcher Objekte darstellt, zB:

public class Job 
{ 
} 

public class JobViewModel 
{ 
    public ObservableCollection<Job> Jobs { get; } = new ObservableCollection<Job>() 
    { 
     new Job(), 
     new Job(), 
     new Job() 
    }; 
} 

Sie dann benutzen, um Ihre Usercontrol (Jobview) in der ItemTemplate des Items:

Mit dieser Stelle können Sie der JobView-Klasse eine ICommand-Eigenschaft hinzufügen, die an eine Befehlseigenschaft des Ansichtsmodells bindet, die die Job-Klasse aus der Quellensammlung entfernt. Bitte beachten Sie den folgenden Beispielcode.

JobViewModel.cs:

public class JobViewModel 
{ 
    public JobViewModel() 
    { 
     RemoveCommand = new DelegateCommand<object>(argument => 
     { 
      Jobs.Remove(argument as Job); 
     }); 
    } 

    public ObservableCollection<Job> Jobs { get; } = new ObservableCollection<Job>() 
    { 
     new Job(), 
     new Job(), 
     new Job() 
    }; 

    public DelegateCommand<object> RemoveCommand { get; } 
} 

JobView.xaml.cs:

public partial class JobView : UserControl 
{ 
    public JobView() 
    { 
     InitializeComponent(); 
    } 

    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(JobView)); 

    public ICommand Command 
    { 
     get { return (ICommand)GetValue(CommandProperty); } 
     set { SetValue(CommandProperty, value); } 
    } 
} 

JobView.xaml:

<UserControl x:Class="WpfApplication1.JobView" 
      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:WpfApplication1" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300" 
      x:Name="uc"> 
    <UserControl.ContextMenu> 
     <ContextMenu> 
      <MenuItem Header="Remove" Command="{Binding PlacementTarget.Command, RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
         CommandParameter="{Binding}"/> 
     </ContextMenu> 
    </UserControl.ContextMenu> 
    <Grid> 
     <TextBlock>job view...</TextBlock> 
    </Grid> 
</UserControl> 

MainWindow.xaml:

<ItemsControl ItemsSource="{Binding Jobs}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <local:JobView Command="{Binding DataContext.RemoveCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Sie müssen die DelegateCommand Klasse selbst implementieren oder Sie die eine in der Prism MVVM-Bibliothek verwenden: https://github.com/PrismLibrary/Prism/blob/master/Source/Prism/Commands/DelegateCommand.cs

Prism installiert werden kann NuGet mit: https://www.nuget.org/packages/Prism.Wpf/.

Sie können hier mehr über das MVVM-Muster lesen: https://msdn.microsoft.com/en-us/library/hh848246.aspx. Ich empfehle Ihnen wirklich, es zu lernen, wenn Sie XAML-Anwendungen entwickeln.