0

I'm developing a small data driven application using C# and MVVMLight and I've run into a problem when trying to add/edit a new item.

Basically, I can set the SelectedMember property to an Member object already in the database in the constructor with no problem:

public MemberDetailViewModel()
{
    _context = new DatabaseEntities();
     GetMembers(); // This just loads the Member objects into an ObservableCollection.
     SelectedMember = _members.FirstOrDefault(); // UI updates as expected.
}

SelectedMember is implemented like this:

public Member SelectedMember
{
    get { return _selectedMember; }
    set { Set(ref _selectedMember, value); }
}

Now this is fine as when I edit the object, all of the data validation works.

However when I go to add a new object using this code:

private void NewMember()
{
    var member = new Member();
    SelectedMember = member; // UI doesn't update, is still on previous object.
}

The UI does not update and it appears that the Member object in SelectedMember is the same one that was loaded in the constructor.

Additionally, When I load an empty object into the SelectedMember property from the constructor, the application doesn't seem to know it exists and no data validation routines fire when I edit the values in the controls:

public MemberDetailViewModel()
{
    _context = new DatabaseEntities();
     SelectedMember = new Member(); // Binding appears to fail, data validation code not firing when control values changed.
}

What am I doing wrong?

Edit: Just looked in the output when the view model actually gets loaded and I've seen this.

System.Windows.Data Error: 40 : BindingExpression path error: 'Centres' property not found on 'object' ''Member_B31A44ECE333F4E7E07BE25FA5BDC79874BAE6C64589F9765ACA373D89BBBD6B' (HashCode=45485186)'. BindingExpression:Path=Centres; DataItem='Member_B31A44ECE333F4E7E07BE25FA5BDC79874BAE6C64589F9765ACA373D89BBBD6B' (HashCode=45485186); target element is 'ComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
System.Windows.Data Warning: 40 : BindingExpression path error: 'SelectedMember' property not found on 'object' ''Member_B31A44ECE333F4E7E07BE25FA5BDC79874BAE6C64589F9765ACA373D89BBBD6B' (HashCode=45485186)'. BindingExpression:Path=SelectedMember.LocalCentre; DataItem='Member_B31A44ECE333F4E7E07BE25FA5BDC79874BAE6C64589F9765ACA373D89BBBD6B' (HashCode=45485186); target element is 'ComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')

I get the feeling I've done something stupid... but what?

Edit 2: The above errors are fixed, but the UI still doesn't update when SelectedMember has changed even with an explicit call to RaisePropertyChanged.

Edit3: Hopefully this is the XAML you need:

<UserControl x:Class="Project.Views.MemberDetailView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:models="clr-namespace:Project.Client.Models"
         mc:Ignorable="d" 
         d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Assets/ResourceDictionaries/DataEntryScreens.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>
<WrapPanel>
    <Expander Header="Personal Information">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Vertical">
                <TextBlock Text="Forename:" />
                <TextBox Text="{Binding SelectedMember.Forename, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
            </StackPanel>
            <!-- Other controls omitted. -->
        </Expander>
    </WrapPanel>
</UserControl>

<!--MemberDetailView.xaml.cs-->
public partial class MemberDetailView : UserControl
{
    public MemberDetailView()
    {
        InitializeComponent();
        this.DataContext = new MemberDetailViewModel();
    }
}
Jake
  • 1,701
  • 3
  • 23
  • 44
  • You need to add some of your XAML - it looks like your bindings aren't correct. We also need some context what your UI looks like - `SelectedMember` implies there is a `Members` collection, and you never add your new item to this. – Charles Mager Jun 01 '15 at 20:45
  • Added the XAML to the main question. I can't figure out mini-markdown for the life of me. – Jake Jun 01 '15 at 21:02

1 Answers1

0

I've solved this... somehow...

I'm not sure what I did but apparently setting a ViewModel in the constructor of the view managed to mess everything up.

So going from this:

public MemberDetailView()
{
    InitializeComponent();
    this.DataContext = new MemberDetailViewModel() { Header = "Members" };
}

to this:

public MemberDetailView()
{
    InitializeComponent();
    //this.DataContext = new MemberDetailViewModel() { Header = "Members" };
}

Has fixed the problem.

Jake
  • 1,701
  • 3
  • 23
  • 44
  • 2
    If it works without then something else (the framework? a parent view?) sets your `DataContext`. By setting it *again* in the constructor, it probably meant your changes were being made to an instance that wasn't bound to your view - hence the updates not being reflected in the view. – Charles Mager Jun 01 '15 at 21:52
  • That's most likely it, everything validates and updates correctly now. At least I got pointed in the right direction. – Jake Jun 01 '15 at 21:54