tags:

views:

64

answers:

2

I have big problem with databinding. I cant bind data to children control. I'm really newbie in MVVM and I spend a lot of hours at this example and I have no idea what is wrong with this Code.

Little explanation:

I have MainWindow. It has UserControl to display list of todo. I want to set my MyWindow class ParentViewModel as DataContext. DataContext has TodoItemModelView as subdatacontext which must be datacontext of UserControlTodoItems.

<Window x:Class="Repo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Repo="clr-namespace:Repo" Title="Window1" Height="300" Width="300">
    <Window.Resources>

        <Repo:ParentViewModel x:Key="parentVM"/>

    </Window.Resources>

    <Window.DataContext>
        <StaticResourceExtension ResourceKey="parentVM"/>
    </Window.DataContext>
    <Grid>
           <Repo:UserControlTodoItems DataContext="{Binding Path=todoItemModelView}">

           </Repo:UserControlTodoItems>
                      </Grid>
</Window>

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
     }



 class ParentViewModel
        {
            public TodoItemModelView todoItemModelView { get; set; } 
            public ParentViewModel()
            {
               this.todoItemModelView=new TodoItemModelView();
            }
        }


public class TodoItemModelView
{
    public ObservableCollection<TodoItem> todoItems { get; set; }

    public TodoItemModelView()
    {
        ObservableCollection<TodoItem> loadedTodoItems = new ObservableCollection<TodoItem>();
        loadedTodoItems.Add(new TodoItem() { Code = "10", ObjectCode = "DE", ObjectType = ObjectType.Country, Status = TodoItemStatus.InProgress, Type = TodoItemType.CollectPhotos });
        loadedTodoItems.Add(new TodoItem() { Code = "11", ObjectCode = "DE", ObjectType = ObjectType.Country, Status = TodoItemStatus.Todo, Type = TodoItemType.DescribeOjbect });
        loadedTodoItems.Add(new TodoItem() { Code = "12", ObjectCode = "DE", ObjectType = ObjectType.Country, Status = TodoItemStatus.Accomplshed, Type = TodoItemType.CollectVideos });
        todoItems = loadedTodoItems;
    }
}

<UserControl x:Class="Repo.UserControlTodoItems"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Repo="clr-namespace:Repo" Height="auto" Width="auto">
    <UserControl.Resources>
        <Repo:TodoItemStatusConverter x:Key="TodoItemStatusConverter"/>

    </UserControl.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Path=todoItems}" Name="lbTasks"> 
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding Path=Status, Converter={StaticResource TodoItemStatusConverter}}"/>
                        <TextBlock Text="{Binding Path=Type}" />
            </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

    </Grid>
</UserControl>


public UserControlTodoItems()
        {
            InitializeComponent();

        }

I correct this.

I must add one question: is there any simple way to inform parentmodel, of change checkbox at listbox?

this is a converter:

public class TodoItemStatusConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {

            TodoItemStatus todoItemStatus = (TodoItemStatus)value;


            if (todoItemStatus == TodoItemStatus.Accomplshed)
            {
                return true;
            }
            else
            {
                return false;
            }



        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
           if ((bool) value)
            {
                return TodoItemStatus.Accomplshed;
            }
            else
            {
                return TodoItemStatus.InProgress;
            }

        }

This is class TodoItem:

public class TodoItem
    {
        public TodoItemType Type { get; set; }

        public TodoItemStatus Status { get; set; }

        public string Code { get; set; }

        public string ObjectCode { get; set; }

        public ObjectType ObjectType { get; set; }
    }
+1  A: 

Why is the binding for your "lbTasks" Listbox just "{Binding}" and not "{Binding Path=todoItems}"

I'm really taking a quick glance at your code here.. you seem to be passing the todoItemModelView as a DataContext properly, but never inform the listbox where in that data context it will find its items.

You may also want to use an ObservableCollection for the list in the VM so you can add and remove todo's in a way the GUI can respond to

astonish
+1  A: 
<CheckBox IsChecked="{Binding Path=Status, Converter={StaticResource TodoItemStatusConverter}}"/>

This implies there is a property on ToDoItemViewModel called Status - but there isn't! Rethink your ToDoItemVm class to just be a wrapper for a toDoItem (ie, public ToDoItemVm(ToDoItem model) and get that array of items into the PArentVm (do use ObservableCollection and bind it to the list box. Also add a SelectedToDoItem property on the ParentVm. So your binding for the list box includes something like

          ItemsSource="{Binding ToDoTems}" 
          IsSynchronizedWithCurrentItem="True"
          SelectedItem="{Binding SelectedToDoItem, Mode=TwoWay}"

Then expose that Status property on your ToDoItemVm, have the class implement INPC, and raise PropertyChanged in the setter.

It may take some work to sort it out, so feel free to ask more questions as you go. The converter idea is fine.

HTH,
Berryl

Berryl
I added description of my class TodoItem. It has field Status. Has it now any sense ? :)