0
votes

I got 2 listviews in the same window The first listView which loads Image thumbnail & Image name. In the second list-view, I want to update the selected image name/name & propose the user to delete or view the selected Images by button click.

I followed this article (http://www.clear-lines.com/blog/post/Selecting-an-item-in-a-list-with-WPF-and-M-V-VM.aspx) but i couldn't succeed to get the selected items by binding. How can i get the selected image name/names from the model.

Code:

//ImageFile Collection Model
 public class ImageFileCollectionViewModel: INotifyPropertyChanged
    {
        private ObservableCollection<ImageFileViewModel> _allImages;
        private int dataItemsCount;

        public ObservableCollection<ImageFileViewModel> AllImages
        {
            get { return _allImages; }
        }

        public int DataItemsCount
        {
            get
            {
                return dataItemsCount;
            }
            private set
            {
                dataItemsCount = value;
                OnPropertyChanged("DataItemsCount");
            }
        }

        public ImageFileCollectionViewModel()
        {
            this._allImages = new ObservableCollection<ImageFileViewModel>();
            this.DataItemsCount = 0;
        }

        public void AddNewPhotoItem(IImageFile imageFile)
        {
            ImageFileViewModel newImageFileViewModel = new ImageFileViewModel(imageFile);
            this._allImages.Add(newImageFileViewModel);
            this.DataItemsCount++;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public ImageFileViewModel ImageFileName { get; set; }// To get the selected Image name
    }

First ListView:

string destination_dir = System.IO.Directory.GetCurrentDirectory() + @"./4x6";
ImageFileCollectionViewModel ImagesViewModel = new ImageFileCollectionViewModel();
ImageFileControler.CompleteViewList(ImagesViewModel, destination_dir);
ListViewImage.DataContext = ImagesViewModel;

Xaml:

 <ListView  SelectionMode="Multiple"  x:Name="ListViewImage" Width="Auto" 
              ItemsSource="{Binding Path=AllImages}"  Margin="0,20,0,0"
              VirtualizingStackPanel.IsVirtualizing="True"
              VirtualizingStackPanel.VirtualizationMode= "Recycling" Height="333" VerticalAlignment="Top">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <DataTemplate.Resources>
                        <Storyboard x:Key="WaitingTimeline" Timeline.DesiredFrameRate="10">
                            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" 
                            Storyboard.TargetName="WaitingImage" 
                            Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0]
                                                       .(RotateTransform.Angle)">
                                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-15"/>
                                <SplineDoubleKeyFrame KeyTime="00:00:03" Value="15"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </DataTemplate.Resources>

                    <StackPanel Orientation="Horizontal" Height="100">

                        <Image x:Name="ThumbnailImage" Margin="2" Visibility="Collapsed" Height="120" Width="180" Source="{Binding Path=Thumbnail}" >
                            <Image.BitmapEffect>
                                <DropShadowBitmapEffect ShadowDepth="5" />
                            </Image.BitmapEffect>

                        </Image>
                        <Image x:Name="WaitingImage" Visibility="Visible" Height="20" Width="20" Source="./Hourglass.png">
                            <Image.RenderTransform>
                                <TransformGroup>
                                    <RotateTransform Angle="0" CenterX="10" CenterY="10"/>
                                </TransformGroup>
                            </Image.RenderTransform>

                        </Image>

                        <TextBlock Margin="10,40,0,0" Text="{Binding Path=ShortName}" />
                    </StackPanel>

                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=IsLoaded}" Value="True">
                            <Setter Property="Visibility" TargetName="ThumbnailImage" Value="Visible"/>
                            <Setter Property="Visibility" TargetName="WaitingImage" Value="Collapsed"/>
                        </DataTrigger>

                        <DataTrigger Binding="{Binding Path=IsLoaded}" Value="False">
                            <Setter Property="Visibility" TargetName="WaitingImage" Value="Visible"/>
                            <Setter Property="Visibility" TargetName="ThumbnailImage" Value="Collapsed"/>
                            <DataTrigger.EnterActions>
                                <BeginStoryboard x:Name="WaitingTimeline_BeginStoryboard" Storyboard="{StaticResource WaitingTimeline}"/>
                            </DataTrigger.EnterActions>
                            <DataTrigger.ExitActions>
                                <StopStoryboard BeginStoryboardName="WaitingTimeline_BeginStoryboard"/>
                            </DataTrigger.ExitActions>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ListView.ItemTemplate>

        </ListView>

Second ListView to get the selected Image Name/names:

<StackPanel Name="secondLBox" Margin="53,369,10,31" Orientation="Vertical"  >
            <ListBox Height="65" 
                Name="ImageNameListBox" 
                ItemsSource="{Binding AllImages}" 
                DisplayMemberPath="LastName"
               SelectedItem="{Binding Path=ImageFileName}"/>
            <Label Content="Selected Image"/>
            <Label Content="{Binding ImageFileName.FileName}" Visibility="Visible" Height="39"/>

        </StackPanel>
2
Additionally to Rohits answer, if ImageViewModel.ImageFileName should contain the item selected in the ListView then I believe you should also bind ListView.SelectedItem to ImageViewModel.ImageFileName. (ListView.SelectedItem uses two-way binding by default) - user2819245

2 Answers

1
votes

Additionally to Rohits answer, if ImageViewModel.ImageFileName should contain the selected item from the ListView then you also need to bind ListView.SelectedItem to ImageViewModel.ImageFileName. (ListView.SelectedItem uses two-way binding by default)

<ListView
    SelectedItem="{Binding Path=ImageFileName}"
    ... all your other stuff from the XAML
/>

ListView.SelectedItem binds two-way by default, so if you change ImageViewModel.ImageFileName via code-behind or through another binding, the selection in the ListView will change accordingly (assuming you also followed Rohit's advice).


You also have an error in the ListBox preventing you to see ImageViewModel.ImageFileName.

Note that the listbox contains items of type ImageViewModel, because of:

<ListBox
    ItemsSource="{Binding AllImages}"
    ...
/>

Now, any possible selected item would also be an ImageViewModel, not ImageViewModel.FileName. Hence, your ListBox should be set up similar to this:

<ListBox Height="65" 
    ItemsSource="{Binding AllImages}" 
    SelectedItem="{Binding ImageFileName}"
    DisplayMemberPath="FileName.LastName"
    ...
/>


UPDATE:

Squinting my eyes very hard, another likely problem was spotted in the code.

The ImageFileCollectionViewModel supposedly serving as DataContext for the ListView and the ListBox is only assigned to ListView.DataContext.

To have the ImageFileCollectionViewModel also applied as DataContext of the ListBox, either assign it explicetly:

ImageFileCollectionViewModel ImagesViewModel = new ImageFileCollectionViewModel();
ImageFileControler.CompleteViewList(ImagesViewModel, destination_dir);
ListViewImage.DataContext = ImagesViewModel;
ImageNameListBox.DataContext = ImagesViewModel;

or just set the DataContext at the parent/ancestor container UIElement, if both the ListView and the ListBox happen to share the same parent/ancestor.

1
votes

Property ImageFileName should raise PropertyChange event on any change in property content so that UI can refresh accordingly.

Declaration should be like this:

private ImageFileViewModel imageFileName;
public ImageFileViewModel ImageFileName
{
   get
   {
      return imageFileName;
   }
   set
   {
      if(imageFileName != value)
      {
         imageFileName = value;
         OnPropertyChanged("ImageFileName");
      }
   }
}

If you want both ListBox to be in sync:

  1. Bind SelectedItem for first ListBox with ImageFileName.
  2. Bind SelectedItem for second ListBox with SelectedItem of first ListBox.

First ListBox:

<ListBox Name="ListViewImage" 
         SelectedItem="{Binding ImageFileName}"/>

Second ListBox:

<ListBox Name="ImageNameListBox" 
         SelectedItem="{Binding SelectedItem, ElementName=ListViewImage}"/>