0

Being a beginner in WPF and MVVM, I have two questions: I build a user control, which is used in a window, and containing two StackPanels.

  1. In the first SP I have a ListView which has edit button and binded to the ViewModel. The edit button is disabled until an ListItem is selected. When an ListItem is selected, all edit buttons are enabeld. How can this be fixed so that only the edit button of the selected ListItem should be enabled. PS. my edit button is a custom control just to get image + text.
  2. The second SP, which will include the edit form of the selected ListItem, the goal is that the edit form becomes visible only when I click on the edit button.

Thank you in advance

Edit Button (Column)

<GridViewColumn Header="Edit" Width="auto">
                                         <GridViewColumn.CellTemplate>
                                           <DataTemplate>

                                                    <cc:MyEditDeleteButton x:Name="BoolToVisibility" 
                                                                           ImageSource="../Images/Edit.png" 
                                                                           Content="Edit" 
                                                                           Command="{Binding EditCommand}" DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}}" 
                                                                           CommandParameter="{Binding Path=SelectedArticle.Id}" 
                                                                           Width="auto"/>

                                            </DataTemplate>
                                        </GridViewColumn.CellTemplate>
                                    </GridViewColumn>

The second StackPanel

<StackPanel Visibility="{Binding ElementName=BoolToVisibility,Path=IsChecked, Converter={ StaticResource BooleanToVisibilityConverter}}">
                            <Label  Content="blablabla"></Label>
                    </StackPanel>

The used converter:

<UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</UserControl.Resources>

The class of my custom control -Edit Button- inherit from ToggleButton

 public class MyEditDeleteButton : ToggleButton
{
    static MyEditDeleteButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyEditDeleteButton), new FrameworkPropertyMetadata(typeof(MyEditDeleteButton)));
    }
    public ImageSource ImageSource
    {
        get { return (ImageSource)GetValue(ImageSourceProperty); }
        set { SetValue(ImageSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ImageSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ImageSourceProperty =
        DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(MyEditDeleteButton), new UIPropertyMetadata(null));

}

So, 2 issues:

  • When an Listitem is selected, edit button will be enabled in the entire column

  • En the visibility of the second stackpanel when the edit button is clicked.

Update.

Thanks guys for your reply. the problem is not completely solved, maybe I'm doing something wrong. here's what I did:

@Ed Plunkett. I don't see how I can claim the _EditItem field.

private Item _editItem;

do you mean the item from the ViewModel? In my view model I have a constructor which has no parameter

Edit item = new Item (item);

<StackPanel>
<StackPanel>
        ... ListView with the Edit Button
</StackPanel>
<StackPanel Visibility="{Binding Mode=OneWay, Source={StaticResource StackCollapsed}}">                        
       <Label  Content="blablabla"></Label>
 </StackPanel>
 </StackPanel>

And in the App.xaml:

<Application.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

        <Style x:Key="StackCollapsed" TargetType="StackPanel">
            <Setter Property="Visibility" Value="Collapsed"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=(viewModels:ArticleViewModel.IsEditable), Converter={ StaticResource BooleanToVisibilityConverter}}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Visible"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
 </Application.Resources>

I still see the StackPanel and it visibility has never changed.

Jongware
  • 22,200
  • 8
  • 54
  • 100
Hicham4
  • 39
  • 1
  • 8
  • 1
    1) [Bind `IsSelected`](http://stackoverflow.com/a/803256/1997232) 2) add `IsEditable` property to item VM, set it to true when button command is executed and bind visibility of edit frame to it, you will also need `SelectedItem` binding (to have something like `Visibility="{Binding SelectedItem.IsEditable, Converter=...}"`). – Sinatr Aug 18 '16 at 14:13
  • Thanks @Sinatr, its does the job. – Hicham4 Sep 06 '16 at 11:24

1 Answers1

0

Here's how I would do this.

First, give the ViewModel an EditItem property with a protected setter. Its type is whatever your item type is. When EditItem is null, hide the editor area.

<StackPanel.Style>
    <Style TargetType="StackPanel">
        <Style.Triggers>
            <DataTrigger Binding="{Binding EditItem}" Value="{x:Null}">
                <Setter Property="Visibility" Value="Collapsed" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</StackPanel.Style>

My EditItemCommand would look a lot like yours in the XAML:

<GridViewColumn.CellTemplate>
    <DataTemplate>
        <Button
            Content="Edit"
            Command="{Binding DataContext.EditItemCommand, RelativeSource={RelativeSource AncestorType=ListView}}"
            CommandParameter="{Binding}"
            IsEnabled="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"
            />
    </DataTemplate>
</GridViewColumn.CellTemplate>

...but in the viewmodel, it would set EditItem to a clone of the command parameter, and store the command parameter in a private field Item _editItemOriginal.

I disagree with your decision to enable the "Edit" button only for the selected row. I'd let the user go straight to the edit button without clicking on the row first. But that's your call, and my IsEnabled binding in the above CellTemplate illustrates an easy way to make that happen.

My SaveEditItemCommand would update _editItemOriginal with any edited properties of its command parameter Item. Its CanExecute code would return true only if its parameter is an Item.

My CancelEditCommand would set EditItem and _editItemOriginal to null. Again, its CanExecute code would return true only if its parameter is an Item.

For all of these commands, I would use a DelegateCommand class which lets me explicitly raise CanExecuteChanged. My EditItem setter would be in charge of that:

#region EditItem Property
private Item _editItem = null;
public Item EditItem
{
    get { return _editItem; }
    protected set
    {
        if (value != _editItem)
        {
            _editItem = value;

            if (_editItem == null)
            {
                _editItemOriginal = null;
            }
            OnPropertyChanged();

            EditItemCommand.RaiseCanExecuteChanged();
            SaveItemCommand.RaiseCanExecuteChanged();
            CancelEditCommand.RaiseCanExecuteChanged();
        }
    }
}

private Item _editItemOriginal;
protected void EditThisItem(Item item)
{
    EditItem = new Item(item);
    _editItemOriginal = item;
}
#endregion EditItem Property