简体   繁体   中英

How can I configure the click event handler of a control for removing itself at its object creation?

Suppose I have two classes: MainWindow and MainWindowViewModel . There is a control called ButtonControl in MainWindow with a click event handler that calls a function in MainWindowViewModel . The function creates Images and then adds them to some WrapPanel's children in the MainWindow. I want to configure a click event handler to the Image Controls at the time they are created so that I can remove the controls from MainWindow when I click on it (MouseLeftButtonUp). How can I do?

MainWindow.xaml

<Windows ...>
<Grid>
<Button Name="ButtonControl" Click="ButtonControl_Click" />
<WrapPanel Name="AttachedPhotosWP" />
</Grid>
</Windows>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private MainWindowViewModel _vm = new MainWindowViewModel();
    public MainWindowViewModel VM{ get { return _vm; } set { _vm= value; } }
    public MainWindow()
    {
       InitializeComponent();
       this.DataContext = VM;      
    }
    private void ButtonControl_Click(object sender, MouseButtonEventArgs e)
    {
        VM.ImageCreation(this);
    }
}

MainWindowViewModel.cs

public class MainWindowViewModel
{
    /* Some other codes */


    public void ImageCreation(MainWindow MW)
    {
         OpenFileDialog openFileDialog = new OpenFileDialog();
         openFileDialog.Multiselect = true;
         openFileDialog.Title = "Select Images...";
         if (openFileDialog.ShowDialog() == true)
         {
              foreach (var file in openFileDialog.FileNames)
              {
                  try
                  {
                      Image img = new Image();
                      BitmapImage imgSrc = new BitmapImage();
                      imgSrc.BeginInit();
                      Uri fileUri = new Uri(file, UriKind.Absolute);
                      imgSrc.UriSource = fileUri;
                      imgSrc.DecodePixelWidth = 100;
                      imgSrc.CacheOption = BitmapCacheOption.OnLoad;
                      imgSrc.EndInit();
                      img.Source = imgSrc;
                      img.Stretch = Stretch.Uniform;
                      img.Height = 70;
                      img.Margin = new Thickness(4, 4, 4, 4);
                      img.MouseLeftButtonUp += ????
                      img.Cursor = Cursors.Hand;
                      MW.AttachedPhotosWP.Children.Add(img);
                  }
                  catch (SecurityException ex) { }
                  catch (Exception ex) { }     
              }
          }
    }

}

Passing a MainWindow reference to the ImageCreation method and creating UI elements in code behind is not at all MVVM.

A basic MVVM solution would use an ItemsControl with an ItemTemplate that contains the Image element. The ItemsSource property of the ItemsControl is bound to an ObservableCollection<ImageSource> . The Image element has an event handler that removes itself from that collection.

<ItemsControl ItemsSource="{Binding ImageFiles}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Image Source="{Binding}"
                   Height="70" Margin="4"
                   MouseLeftButtonUp="Image_MouseLeftButtonUp"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
...
<Button Content="Load Images..." Click="LoadButton_Click"/>

The MainWindow class and the view model would look like this:

public partial class MainWindow : Window
{
    private readonly ViewModel viewModel = new ViewModel();

    public MainWindow()
    {
        DataContext = viewModel;
        InitializeComponent();
    }

    private void LoadButton_Click(object sender, RoutedEventArgs e)
    {
        var openFileDialog = new OpenFileDialog();
        openFileDialog.Multiselect = true;
        openFileDialog.Title = "Select Images...";
        openFileDialog.Filter = "JPEG Files (*.jpg)|*.jpg|PNG Files (*.png)|*.png";

        if (openFileDialog.ShowDialog() == true)
        {
            viewModel.LoadImages(openFileDialog.FileNames);
        }
    }

    private void Image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        var image = (Image)sender;
        viewModel.ImageFiles.Remove(image.Source);
    }
}

public class ViewModel
{
    public ObservableCollection<ImageSource> ImageFiles { get; }
        = new ObservableCollection<ImageSource>();

    public void LoadImages(IEnumerable<string> imageFiles)
    {
        ImageFiles.Clear();

        foreach (var imageFile in imageFiles)
        {
            var image = new BitmapImage();
            image.BeginInit();
            image.UriSource = new Uri(imageFile, UriKind.RelativeOrAbsolute);
            image.DecodePixelWidth = 100;
            image.EndInit();
            ImageFiles.Add(image);
        }
    }
}

You may further improve this by replacing the Image with mouse event handler by a Button that uses an Image element in its ControlTemplate, and that has its Command property bound to an ICommand property in your view model. That command would remove the current image from the source collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM