How can i update items from ListView with Caliburn.Micro in C#?
Asked Answered
S

1

2

I wrote a simple program with MVVM (C#) and XAML using Caliburn.Micro library, But some actions didn't work:

  • update an item content
  • get selected item
  • get specific item
  • move up and move down records
  • enable or disable buttons when Add button clicked

Any help would be appreciated.

My GUI code:

// Views\MainView.xaml
<Window x:Class="ListBox_CaliburnMicro.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:vm="clr-namespace:ListBox_CaliburnMicro"
        WindowStartupLocation="CenterScreen"
        Title="MainWindow" Height="300" Width="600">
    <Grid>
        <Grid.DataContext>
            <vm:MainViewModel/>
        </Grid.DataContext>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="153*"/>
        </Grid.ColumnDefinitions>

        <Button Content="Add" Command="{Binding AddCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="10,37,0,0" VerticalAlignment="Top" Width="75" ToolTip="Add item end of list" Background="White" Foreground="Black" Height="22"/>
        <Button Content="Delete" Command="{Binding DeleteCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="96,37,0,0" VerticalAlignment="Top" Width="75" ToolTip="Delete first item from list" Background="White" Foreground="Black" Height="22"/>
        <Button Content="Update" Command="{Binding UpdateCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="184,37,0,0" VerticalAlignment="Top" Width="75" ToolTip="Update first item from list" Background="White" Foreground="Black" Height="22"/>
        <Button Content="GetSelectedItem" Command="{Binding GetSelectedItemCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="271,37,0,0" VerticalAlignment="Top" Width="95" ToolTip="get selected item from list" Background="White" Foreground="Black" Height="22"/>
        <Button Content="GetItem:" Command="{Binding GetItemXCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="377,37,0,0" VerticalAlignment="Top" Width="75" ToolTip="get item x, from list" Background="White" Foreground="Black" Height="22"/>

        <TextBox Grid.Column="1" x:Name="ItemX" Text="0" HorizontalAlignment="Left" Height="24" Margin="457,35,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="70"/>

        <ListView Grid.Column="1" x:Name="FileListView" ItemsSource="{Binding Path=Files}" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" Margin="10,65,10,10" Foreground="Black" Background="#FFE6EEF7">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Status" Width="Auto"
                    DisplayMemberBinding="{Binding FileStatus}"/>
                    <GridViewColumn Header="Name" Width="Auto"
                    DisplayMemberBinding="{Binding FileName}"/>
                    <GridViewColumn Header="Size" Width="Auto"
                     DisplayMemberBinding="{Binding FileSize}"/>
                    <GridViewColumn Header="System Type" Width="Auto"
                    DisplayMemberBinding="{Binding FileType}"/>
                    <GridViewColumn Header="Email Count" Width="Auto"
                     DisplayMemberBinding="{Binding FileEmailCount}"/>
                    <GridViewColumn Header="Info Count" Width="Auto"
                     DisplayMemberBinding="{Binding FileInfoCount}"/>
                </GridView>
            </ListView.View>
        </ListView>

    </Grid>
</Window>

My model is:

// Model\File.cs
using System;

namespace ListBox_CaliburnMicro.Model
{
    public class File
    {
        private Guid _FileID;
        public Guid FileID
        {
            get
            {
                return _FileID;
            }
            set 
            {
                _FileID = value;
            }
        }
        public string FileStatus { get; set; }
        public string FileName { get; set; }
        public string FileSize { get; set; }
        public string FileType { get; set; }
        public string FileEmailCount { get; set; }
        public string FileInfoCount { get; set; }

        public File()
        {
            FileID = Guid.NewGuid();
        }
        public File(string s1 = "", string s2 = "", string s3 = "", string s4 = "", string s5 = "", string s6 = "")
        {
            FileID = Guid.NewGuid();

            FileStatus = s1;
            FileName = s2;
            FileSize = s3;
            FileType = s4;
            FileEmailCount = s5;
            FileInfoCount = s6;
        }
    }
}

My command handler code:

// ViewModels\CommandHandler.cs
using System;
using System.Windows.Input;

namespace ListBox_CaliburnMicro.ViewModels
{
    public class CommandHandler : ICommand
    {
        private System.Action _action;
        private bool _canExecute;
        public CommandHandler(System.Action action, bool canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }
        public bool CanExecute(object parameter)
        {
            return _canExecute;
        }

        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
            _action();
        }
    }
}

And my ViewModel:

// ViewModels\MainViewModel.cs
using Caliburn.Micro;
using ListBox_CaliburnMicro.Model;
using ListBox_CaliburnMicro.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace ListBox_CaliburnMicro
{
    public class MainViewModel : Screen, INotifyPropertyChanged
    {
        public MainViewModel()
        {
            FillDataFile();

            _canAddCommandExecute = true;
            _canDeleteCommandExecute = false;
            _canUpdateCommandExecute = false;
            _canGetSelectedItemCommandExecute = false;
            _canGetItemXCommandExecute = false;
        }

        #region File listView
        private ObservableCollection<File> _Files;
        public ObservableCollection<File> Files
        {
            get { return _Files; }
            set 
            {
                _Files = value;
                OnPropertyChanged("Files");
            }
        }

        private void FillDataFile()
        {
            _Files = new ObservableCollection<File>();
            for (int i = 0; i < 0; i++)
            {
                _Files.Add(new File() { FileStatus = "status", FileName = "name", FileSize = "size", FileType = "type", FileEmailCount = "email_count", FileInfoCount = "info_count" });
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

        #region ItemX textbox
        private string _ItemX = "0";
        public string ItemX
        {
            get 
            {
                return _ItemX;
            }
            set 
            {
                _ItemX = value;
            }
        }
        #endregion

        #region command button

        #region Add button with Command
        private ICommand _AddCommand;
        public ICommand AddCommand
        {
            get
            {
                return _AddCommand ?? (_AddCommand = new CommandHandler(() => AddAction(), _canAddCommandExecute));
            }
        }

        static int nIndex = 0;

        private bool _canAddCommandExecute;
        public void AddAction()
        {
            string strName = string.Format("{0}", nIndex++);
            _Files.Add(new File() { FileStatus = "status", FileName = strName, FileSize = "size", FileType = "type", FileEmailCount = "email_count", FileInfoCount = "info_count" });

            // enabled action buttons,
            // !!! but not worded !!!
            _canAddCommandExecute = true;
            _canDeleteCommandExecute = true;
            _canUpdateCommandExecute = true;
            _canGetSelectedItemCommandExecute = true;
            _canGetItemXCommandExecute = true;


        }
        #endregion

        #region Delete button with Command
        private ICommand _DeleteCommand;
        public ICommand DeleteCommand
        {
            get
            {
                return _DeleteCommand ?? (_DeleteCommand = new CommandHandler(() => DeleteAction(), _canDeleteCommandExecute));
            }
        }

        private bool _canDeleteCommandExecute;
        public void DeleteAction()
        {
            if (_Files.Count > 0)
                _Files.RemoveAt(0);
        }
        #endregion

        #region Update button with Command
        private ICommand _UpdateCommand;
        public ICommand UpdateCommand
        {
            get
            {
                return _UpdateCommand ?? (_UpdateCommand = new CommandHandler(() => UpdateAction(), _canUpdateCommandExecute));
            }
        }

        private bool _canUpdateCommandExecute;
        public void UpdateAction()
        {
            if (_Files.Count > 0)
            {
                // update FileName field
                _Files[0].FileName = "+"; // !!! but didn't work !!!

                // List<File> FilesSelect = _Files.Where(p => p.FileID == _Files[0].FileID).ToList();
            }
        }
        #endregion

        #region GetSelectedItem button with Command
        private ICommand _GetSelectedItemCommand;
        public ICommand GetSelectedItemCommand
        {
            get
            {
                return _GetSelectedItemCommand ?? (_GetSelectedItemCommand = new CommandHandler(() => GetSelectedItemAction(), _canGetSelectedItemCommandExecute));
            }
        }

        private bool _canGetSelectedItemCommandExecute;
        public void GetSelectedItemAction()
        {
            if (_Files.Count > 0)
            {
                // ... get selected item in ListView
            }
        }
        #endregion

        #region GetItemX button with Command
        private ICommand _GetItemXCommand;
        public ICommand GetItemXCommand
        {
            get
            {
                return _GetItemXCommand ?? (_GetItemXCommand = new CommandHandler(() => GetItemXAction(), _canGetItemXCommandExecute));
            }
        }

        private bool _canGetItemXCommandExecute;
        public void GetItemXAction()
        {
            if (_Files.Count > 0)
            {
                // ... get item 'X' that enter in TextBox control
            }
        }
        #endregion

        #endregion
    }
}
Shortsighted answered 3/2, 2016 at 10:22 Comment(3)
what do you mean "up and down records"?Bashaw
@Bashaw excuse me, i mean MoveUp and Movedown.Shortsighted
It is better to ask new questions about how to "get specific item" and how to "move up and move down records" as it is not enough information about what you want.Bashaw
B
3

Update an item content. To see an updated item of model in your view, then you should implement INotifyPropertyChanged event in EACH property of your model. For example:

public class File:INotifyPropertyChanged
{
    private Guid _FileID;
    public Guid FileID
    {
        get
        {
            return _FileID;
        }
        set 
        {
            _FileID = value;
            OnPropertyChanged("FileID");
        }
    }

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

Get selected item. Create a Property in the ViewModel for saving the selected item, for instance File:

public File SelectedFile { get; set; }

then bind SelectedItem of the ListView to this property:

<ListView Name="UserGrid" SelectedItem="{Binding SelectedFile}"  
 ItemsSource="{Binding Path=Files}"/>

After you've implemented SelectedFile property, you can take the value like that:

if(SelectedFile!=null)
    var exactFile=SelectedFile;

Enable or disable buttons when Add button clicked. You have two ways: With Caliburn and without Caliburn

With CaliburnMicro: CaliburnMicro has own mechanism to handle Button Click event. For instance:

<Button Content="ShowPageTwo">
     <i:Interaction.Triggers>
         <i:EventTrigger EventName="Click">
              <cal:ActionMessage MethodName="ShowPageTwo" />
         </i:EventTrigger>
     </i:Interaction.Triggers>
</Button>

To see more details about implementation, please see official guide at CodePlex.

Without CaliburnMicro:

At first you should create RelayCommand class to relay its functionality to other objects by invoking delegates:

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}

Then create a property in your viewModel. For instance:

public class YourViewModel
{
    public RelayCommand YourCommand { get; set; }
    public YourViewModel()
    {
        YourCommand = new RelayCommand(DoSmth, CanDoSmth);
    }

    private void DoSmth(object obj)
    {
        Message.Box("Hello from viewModel"); 
    }

    private bool CanDoSmth(object obj)
    {
       //you could implement your logic here. But by default it should be  
       //set to true
       return true;
    }
}

And XAML should be look like:

<Button Content="Click me!" Command="{Binding LoginCommand}"/> 
Bashaw answered 3/2, 2016 at 11:34 Comment(10)
thanks a lot @StepUp. But I did not mean how to handle click event. I meant how to enable (or disable) buttons so it can not be clicked?Shortsighted
@Shortsighted please give more attention to the article, especially where method CanSayHello is describedBashaw
In my previous question you said use Commands to handle button click event, I did what you said and it worked. but this time I want to disable button in its first appearance when the form loads and enable it again after one record is added to listview. I hope I delivered the point :)Shortsighted
Thank you @Bashaw it's work. but what was the point? to achieve my request, must use without CaliburnMicro!Shortsighted
there are two approaches to implement Command bindings if you use CaliburnMicro. I mean if you use Caliburnmicro, it is better to use CaliburnMicro approach.Bashaw
Codeplex is no longer updated!... github.com/Caliburn-Micro/Caliburn.Micro Documentation is located caliburmicro.comNumerical
Thanks alot @StepUp, if it's not a burden, my preference is to use Caliburn.Micro approach, but i wasn't able to do so. Could you help me with this matter?Shortsighted
@StepUp, I could get selected item, but only first selected item, 1. how can i get "all selected items"? 2. how can i get "selection changed" event? 3. how can i sort items by click on each header columns?Shortsighted
@Shortsighted it is better to create a new question to get answers for questions. please read this post wikihow.com/Ask-a-Question-on-Stack-OverflowBashaw
I ask new question with this link @Bashaw , linkShortsighted

© 2022 - 2024 — McMap. All rights reserved.