Rohit
Rohit

Reputation: 10236

How to bind button to Listbox item

ViewModel

  public class MainWindowViewModel:BindableBase
  {
     public IRelayCommand MyCommand { get; protected set; }


    private void CreateCommand()
    {

        this.MyCommand = new RelayCommand(MyCommandExecuted, CanExecuteMyCommand);
    }

    private void MyCommandExecuted(object obj)
    {
        MessageBox.Show("Command Executed");
    }

    private bool CanExecuteMyCommand(object obj)
    {
        return true; // The value is based on Selected Item
    }
  }

XAML

     <ListBox
             x:Name="myListBox" 
             ItemsSource="{Binding Path=MyClass}"
             <ListBox.ItemTemplate>
        <DataTemplate>
                <Expander Header="{Binding Path=HeaderName}" IsExpanded="True">
                    <StackPanel>
                        <DataGrid
                             x:Name="dataGrid"

                             AutoGenerateColumns="False"
                             ItemsSource="{Binding Path=RowVal}"  SelectedItem="{Binding CurrentItem}"/>
                    </StackPanel>
                </Expander>
        </DataTemplate>
        </ListBox.ItemTemplate>

<Button Content="Select" 

            Command="{Binding Path=MyCommand }" 
            CommandParameter="{Binding ElementName=myListBox,Path=SelectedItem}"/>

DataClass

  public class DataClass 
   {
    public string HeaderName { get; set; }
    public object RowVal { get; set; }
    public ObservableCollection<DataGridColumn> ColumnCollection { get; set;}
    private object currentItem;

    public object CurrentItem
    {
        get
        {
            return currentItem;
        }
        set
        {
            currentItem = value;

        }
    }

}

How can I bind my button to Listbox item which is CurrentItem in DataClass ?

Upvotes: 0

Views: 1471

Answers (3)

default
default

Reputation: 11635

I created a complete example to show how I would do it. You would have to bind the parent element to SelectedItem as well, to keep track of when that item changes. Since the SelectedItem is public in your child class as well you can access that when your command triggers in your main view model.

<Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition />
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding Parents}" SelectedItem="{Binding SelectedParent}">
    <ListView.ItemTemplate>
        <DataTemplate DataType="{x:Type local:Parent}">
            <DataGrid ItemsSource="{Binding Children}" SelectedItem="{Binding SelectedChild}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
<Button Grid.Row="1" Width="70" Content="Click me" Height="25" Command="{Binding MyCommand}" />

i.e. in DoWork, you can get the child from the parent via its public property.

public sealed class WindowViewModel : INotifyPropertyChanged
{
    private readonly ObservableCollection<Parent> parents;
    private readonly ICommand myCommand;
    private Parent selectedParent;

    public WindowViewModel()
    {
        parents = new ObservableCollection<Parent>
        {
            new Parent{ Name = "P1"},
            new Parent{ Name = "P2"}
        };
        myCommand = new DelegateCommand(DoWork);
    }

    private void DoWork()
    {
        var selectedChild = SelectedParent == null ? null : SelectedParent.SelectedChild;

    }

    public Parent SelectedParent
    {
        get { return selectedParent; }
        set
        {
            if (selectedParent == value)
                return;
            selectedParent = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<Parent> Parents
    {
        get { return parents; }
    }

    public ICommand MyCommand
    {
        get { return myCommand; }
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

With the basic setup of Data models

public class Parent : INotifyPropertyChanged
{
    private ObservableCollection<Child> children;
    private Child m_SelectedChild;


    public Parent()
    {
        children = new ObservableCollection<Child>
        {
            new Child {Name = "C1"},
            new Child {Name = "C2"}
        };
    }

    public string Name { get; set; }

    public ObservableCollection<Child> Children
    {
        get { return children; }
    }

    public Child SelectedChild
    {
        get { return m_SelectedChild; }
        set
        {
            if (m_SelectedChild == value)
                return;
            m_SelectedChild = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Child
{
    public string Name { get; set; }
}

Another solution, if you are more interested of the Child item in your WindowViewModel is to change the relative source of where the binding should occur, in your DataGrid. i.e., the binding would look like this instead:

<DataGrid ItemsSource="{Binding Children}"
          SelectedItem="{Binding DataContext.SelectedChild, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" />

and then move the Property from Parent to WindowViewModel. With that you would be able to trigger changes to your button command when the child element changes for any of the Parent elements.

Upvotes: 1

Amol Bavannavar
Amol Bavannavar

Reputation: 2062

Try this :

    CommandParameter="{Binding ElementName=myListBox,Path=SelectedItem.CurrentItem}"

Upvotes: 0

Tomtom
Tomtom

Reputation: 9384

I think you want to pass the CurrentItem to the MyCommand as CommandParameter right?

Then you only have to:

CommandParameter="{Binding CurrentItem, UpdateSourceTrigger=PropertyChanged}"

Upvotes: 0

Related Questions