picoe / Eto

Cross platform GUI framework for desktop and mobile applications in .NET
Other
3.67k stars 335 forks source link

MonoMac: GridView doesn't update UI after changes are made in collection #515

Open nast90210 opened 8 years ago

nast90210 commented 8 years ago

If i right understand the API: GridView "...supports MVVM in such that if the collection implements INotifyCollectionChanged, such as the ObservableCollection, it will update as changes are made to the underlying collection.". But in my code it doesn't work, and i have to use Invalidate() to see changes. It only happen in MonoMac; in Gtk# all works fine without Invalidate().

Sample:

public class MainForm : Form
{
    List<string> filenames = new List<string>();
    GridView grid = new GridView();
    ObservableCollection<GridDate> collection = new ObservableCollection<GridDate>();

    Button openButton = new Button();
    Button startButton = new Button();
    Button deleteButton = new Button();
    Label status = new Label();

    public MainForm ()
    {
        ClientSize = new Size (500, 350);
        MinimumSize = new Size (500, 350);

        Menu = new MenuBar ();

        var layout = new TableLayout (1,3);
        var buttons = new TableLayout (3, 1);

        buttons.Spacing = new Size (5, 5);
        buttons.Padding = new Padding (5);

        buttons.Add (openButton, 0, 0, true, false);
        buttons.Add (startButton, 1, 0, true, false);
        buttons.Add (deleteButton, 2, 0, true, false);

        layout.Add (buttons, 0, 0, true, false);
        layout.Add (grid, 0, 1, true, true);
        layout.Add (status, 0, 2, true, false);

        openButton.Text = "Открыть";
        openButton.Click += OpenButton_Click;

        startButton.Text = "Разбить";
        startButton.Click += StartButton_Click;
        startButton.Enabled = false;

        deleteButton.Text = "Удалить";
        deleteButton.Click += DeleteButton_Click;
        deleteButton.Enabled = false;

        grid.AllowMultipleSelection = true;
        grid.Enabled = false;

        grid.DataStore = collection;

        grid.SelectionChanged += (sender, e) => {
            if(!isParsing){
                List<int> i = new List<int>();
                foreach(var x in grid.SelectedRows){
                    i.Add(x);
                }
                if (i.Count>0) deleteButton.Enabled = true;
                else deleteButton.Enabled = false;
                Invalidate();
            }
        };

        grid.Columns.Add(new GridColumn {
            DataCell = new TextBoxCell { Binding = Binding.Property<GridDate, string>(r => r.Number) },
            HeaderText = "#",
        });

        grid.Columns.Add(new GridColumn {
            DataCell = new TextBoxCell { Binding = Binding.Property<GridDate, string>(r => r.Name) },
            HeaderText = "Файл",
            AutoSize = true,
        });

        grid.Columns.Add (new GridColumn {
            DataCell = new ProgressCell { Binding = Binding.Property<GridDate, float?>(r => r.Progress) },
            HeaderText = "Статус",
            Width = 400,
            AutoSize = true,
        });

        Content = layout;
    }

    void DeleteButton_Click (object sender, EventArgs e)
    {
        List<int> i = new List<int>();
        foreach(var x in grid.SelectedRows){
            i.Add(x);
        }
        int temp = 0;
        foreach(var x in i){
            collection.RemoveAt (x-temp);
            filenames.RemoveAt (x-temp);
            count--;
            temp++;
        }

        if (filenames.Count == 0)
            startButton.Enabled = false;

        NumberRefresh ();
        Invalidate();

    }

    private void NumberRefresh()
    {
        grid.SelectAll ();
        int index = 1;
        foreach (var i in grid.SelectedItems) {
            var cell = i as GridDate;
            cell.Number = index.ToString();
            index++;
        }
        grid.UnselectAll ();
        Invalidate();
    }

    void StartButton_Click (object sender, EventArgs e)
    {
        openButton.Enabled = false;
        startButton.Enabled = false;
        deleteButton.Enabled = false;
        initWork();
    }

    void OpenButton_Click (object sender, EventArgs e)
    {
        OpenFileDialog ofd = new OpenFileDialog ();
        ofd.MultiSelect = true;
        ofd.Title = "Выберите файлы";

        if (ofd.ShowDialog (this) == DialogResult.Ok) {
            foreach (string filename in ofd.Filenames) {
                if (!filenames.Contains (filename) || filename.Length > 2000000000) {
                    filenames.Add (filename);
                    collection.Add (new GridDate { Number = count.ToString (), Name = System.IO.Path.GetFileNameWithoutExtension (filename),
                        Progress = null
                    });
                    count++;
                    grid.Enabled = true;
                    startButton.Enabled = true;
                } else {
                    MessageBox.Show ("Файл " + System.IO.Path.GetFileNameWithoutExtension (filename) 
                        + " уже есть в списке", "Ошибка", MessageBoxButtons.OK, MessageBoxType.Error , MessageBoxDefaultButton.OK);
                }
            }
        }
        Invalidate();
    }

    class GridDate
    {
        public string Number { get; set; }
        public string Name { get; set; }
        public float? Progress { get; set; }
    }
lth3726381 commented 8 years ago

Same problem on OS X 10.11.4 ,now I have to call Invalidate repeatly.

veraciousnottaken commented 8 years ago

ObservableCollection not noticing when Item in it changes

class GridDate : INotifyPropertyChanged
    {
        private string _number;
        public string Name { get; set; }
        public float? Progress { get; set; }

public string Number
        {
            get { return _number; }
            set
            {
                if (value != _number)
                {
                    _number = value;
                    //Log.Write(this, "Changed value of {0} to {1}", Name, val);
                    OnPropertyChanged("Number");
                }
            }
        }
        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }