Датагрид привязка МВВМ

1

Я очень новичок в MVVM, и я просто пытаюсь намочить ноги небольшим приложением тестирования wpf. У меня есть модельный вызов ToDoItemModel, определенный ниже: (в основном у меня есть класс под названием ToDoItemModel и ToDoItemListModel, который реализует IList

public class ToDoItemModel
{
    private DateTime    _TodoDate;
    private string      _TodoDescription;
    private TimeSpan    _TodoTimeSpan;
    private string      _StartTime;

    public ToDoItemModel(DateTime d, string s)
    {
        _TodoDate=d;
        _TodoDescription=s;
    }

    public string StartTime
    {
        get { return      _StartTime; }
        set {      _StartTime = value; }
    }


    public TimeSpan ToDoTimeSpan
    {
        get { return _TodoTimeSpan; }
        set { _TodoTimeSpan = value; }
    }

    public string ToDoDescription
    {
        get { return _TodoDescription; }
        set { _TodoDescription = value; }
    }

    public DateTime ToDoDate
    {
        get { return _TodoDate; }
        set { _TodoDate = value; }
    }

    public override string ToString()
    {
        return string.Format("Date: {0}- Time: {1}- Duration: {2}- Description: {3}",_TodoDate.ToString("d"),_StartTime,_TodoTimeSpan,_TodoDescription);
    }       
}

public class ToDoListModel: IList<ToDoItemModel>
{
    private readonly IList<ToDoItemModel> _todoList = new List<ToDoItemModel>();

    public ToDoListModel()
    {
         //Hard code this one for testing purpose
        _todoList.Add(new ToDoItemModel(DateTime.Now,"Testing"));
    }

    public int IndexOf(ToDoItemModel item)
    {
        return _todoList.IndexOf(item);
    }

    public void Insert(int index, ToDoItemModel item)
    {
        _todoList.Insert(index,item);
    }

    public void RemoveAt(int index)
    {
        _todoList.RemoveAt(index);
    }

    public ToDoItemModel this[int index]
    {
        get
        {
            return _todoList[index];
        }
        set
        {
            _todoList[index]=value;
        }
    }

    public void Add(ToDoItemModel item)
    {
        _todoList.Add(item);
    }

    public void Clear()
    {
        _todoList.Clear();
    }

    public bool Contains(ToDoItemModel item)
    {
        return _todoList.Contains(item);
    }

    public void CopyTo(ToDoItemModel[] array, int arrayIndex)
    {
        _todoList.CopyTo(array,arrayIndex);
    }

    public int Count
    {
        get { return _todoList.Count; }
    }

    public bool IsReadOnly
    {
        get { return _todoList.IsReadOnly; }
    }

    public bool Remove(ToDoItemModel item)
    {
        return _todoList.Remove(item);
    }

    public IEnumerator<ToDoItemModel> GetEnumerator()
    {
        return _todoList.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Я хотел бы отобразить на моем представлении datagrid, который будет привязан к ToDoListModel через ToDoListModelView, который наследуется от ObservableObject. ObservableObject реализует INotifyPropertyChanged

public class ToDoListModelView:ObservableObject
{
    ToDoListModel _myModel = new ToDoListModel();
    ...
}

Мое мнение определяется кодом xaml ниже: В принципе, я хотел бы привязать этот datagrid к моей ToDoListModel.

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestWPF" x:Class="TestWPF.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="1,0,-1,0">
        <DataGrid x:Name="ExistingToDoList" 
          HorizontalAlignment="Left" 
          Margin="33,201,0,0" 
          VerticalAlignment="Top" 
          Height="94" Width="464" 
          Background="#FFF1E6E6" 
          GridLinesVisibility="Horizontal" 
          ItemsSource="{Binding ToDoListModelView}" 
          Style="{DynamicResource ToDoEntry}">
            <DataGrid.DataContext>
                <local:ToDoListModel/>
            </DataGrid.DataContext>
        </DataGrid>
    </Grid>
</Window>

Однако после нажатия F5 программа запустилась, но я не вижу содержимого, связанного с данными, хотя у меня есть как минимум 1 элемент в списке. Что я сделал неправильно? Я знаю, что это далеко не полный, но, по крайней мере, я должен увидеть ToDoItem в списке из datagrid? Что я пропустил? Пожалуйста помоги. Благодарю!

---- Мое обновление -------------------------------------------- -

ToDoListModel наследует от List с свойством ToDoList, который возвращает базовые данные

public class ToDoListModel: List<ToDoItemModel>
{
    private  List<ToDoItemModel> _todoList = new List<ToDoItemModel>();
    public List<ToDoItemModel> TodoList
    {
        get { return _todoList; }
    }

    public ToDoListModel()
    {
        _todoList.Add(new ToDoItemModel(DateTime.Now,"Testing"));
    }

Я также исправил datagrid для привязки к ToDoList и установил autoGeneratecolumn в true для простоты и иллюстрации.

<Grid Margin="1,0,-1,0" d:DataContext="{d:DesignData /SampleData/ToDoListModelSampleData.xaml}">
    <DataGrid x:Name="ExistingToDoList" 
        HorizontalAlignment="Left" 
        Margin="33,201,0,0" 
        VerticalAlignment="Top" 
        Height="94" Width="464" 
        Background="#FFF1E6E6" 
        GridLinesVisibility="Horizontal" 
        ItemsSource="{Binding TodoList}" 
        Style="{DynamicResource ToDoEntry}" 
        AutoGenerateColumns="True"
        DataContext="{Binding Mode=OneWay}">
        <DataGrid.ItemBindingGroup>
            <BindingGroup/>
        </DataGrid.ItemBindingGroup>
    </DataGrid>
Теги:
xaml
wpf
mvvm
datagrid

1 ответ

1
Лучший ответ

Вы устанавливаете свойство DataContext классу "Model" (что-то, чего вы никогда не должны делать, всегда устанавливаете в класс ViewModel), который не имеет свойства "ToDoListModelView", поэтому привязка не работает (вы должны увидеть это как Систему. Исключение данных в окне вывода).

Writing ItemsSource="{Binding ToDoListModelView}" говорит: "Ищите свойство, называемое" ToDoListModelView "в моем DataContext, и используйте его как мой ItemSource". Вероятно, вы планировали:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestWPF" x:Class="TestWPF.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
       <local:ToDoListModelView/>
    </Window.DataContext>
    <Grid Margin="1,0,-1,0">
        <DataGrid x:Name="ExistingToDoList" 
          ItemsSource="{Binding MyModelProperty}" 
        </DataGrid>
    </Grid>
</Window>

Обратите внимание, что я установил DataContext в объект ViewModel (а не в модель), и я установил его для окна. Это чисто стилистика, но вы обычно не устанавливаете специфическое свойство DataContext управления (хотя бывают случаи, когда это необходимо). Затем я связываюсь с (воображаемым) свойством, которое, вероятно, будет экземпляром ToDoListModel.

Несколько других сторон:

  1. Если вы наследуете IList вы, вероятно, ошибаетесь! Что случилось с ObservableCollection или одной из других существующих реализаций?
  2. Его "ViewModel" не "ModelView", как соглашение об именах

Аналогичный, но не дубликат (ответ может помочь вам: установка DataContext в XAML в WPF)

  • 0
    спасибо за указание на проблемную область в моем коде. ILIST определенно является излишним для этого случая. Я изменил его на LIST <T> и соглашение об именах тоже. Я полностью зелен в этом. То, что я до сих пор немного неясен, это привязка ItemsSource: нужно ли связать его со строкой или со всем классом? Допустим, если я изменю свой класс ToDoListModel: List <ToDoItemModel> со свойством ToDoList, которое возвращает весь List <ToDoModel>, и свойством скажем ToDoListAt (index). Когда я связываю ресурс источников, я должен связать его с ToDoList или ToDoListAt? Нужно ли определять каждое поле в сетке данных?
  • 0
    Вы привязываетесь к «ToDoList» (ItemsSource всегда привязан к коллекции), и да, вам нужно определить каждое поле (AutoGenerateColumns может работать, но вы почти всегда хотите, чтобы оно было пользовательским). Имеет ли это смысл?
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню