简体   繁体   中英

Binding Command to ListView Items MVVM proper way

I have an application list which is bound to a ListView control.

private List<_Application> _applicationList;

public List<_Application> applicationList
{
    get { return _applicationList; }
    set
    {
        _applicationList = value;
        OnPropertyChanged();
    }
}

The ListView ItemTemplate is set as a button.

<ListView ItemsSource="{Binding applicationList}"
          BorderThickness="5"
          Style="{DynamicResource ListViewStyle}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Button Command="{Binding RunCommand}" 
                    Style="{StaticResource ApplicationButtonStyle}" 
                    Content="{Binding name}" 
                    Background="{Binding colorRGB}" >
            </Button>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

When I click on the button I want an application to be executed. My Model _Application contains an ActionCommand that runs the process.

public class _Application
{
    public ActionCommand RunCommand
    {
        get { return new ActionCommand(action => Run()); }
    }

    private void Run()
    {
        Process p = new Process();
        p.StartInfo.FileName = path;

        try
        {
            p.Start();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    public _Application()
    {
    }
}

I am not sure, is it correct keeping the ActionCommand in the Model?

How could I correctly implement this in the MVVM pattern?

Where should the ActionCommand be placed and how to bind it to the ListView of Buttons so the correct _Application will be run?

I think the best way is pass the model ( _Application ) like a parameter to the command.

RunCommand = new RelayCommand(param => this.OnRun(param));

Command action

private void OnRun(_Application app)
{
     //Any action with your model
}

Xaml

Command="{Binding DataContext.RunCommand, ElementName=PageRootKey}"
CommandParameter="{Binding Mode=OneWay}">

First of all you should use ICommand and not ActionCommand from one simple reason, if in the future you will want to replace the ActionCommand in something better that implements ICommand you won`t need to replace so many places in the code.

    public ICommand RunCommand
    {
        get
        { return new ActionCommand(Run); }
    }

The correct _Application will run as each item in the list view is connected to single _Application item in the collection.

Note: in above code I wrote ...ActionCommand(Run); since ActionCommand accepts an Action parameter you can write the code shortly and more readable like this.

I assume of course in the complete code _Application has properties of name and colorRgb. As a matter of fact, if you wish to use correct MVVM pattern then colorRgb should not be in the viewmodel or the model. It is a view term. You should use a converter (read IValueConverter) to set a different color for each button (although it is not UX friendly).

And one last thing, property like name should be Name (capital N) as property names in C# should always begin with capital letters.

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