2

In the application I wanted to bind data from 2 different viewmodels. Which is I have to set datacontext to two different viewmodels.

When I did with two different viewmodels, only the last set datacontext is taking precedence.

Hence, I have a CombinedDataContext class with other viewmodel classes.

I could able to update to viewmodel, but it is not getting displayed onto views.

ViewModel1

public class Data1 : INotifyPropertyChanged
    {
        private string _string1;

        public string String1
        {
            get { return _string1; }
            set { _string1 = value; onPropertyChnaged("String1"); }
        }

        private void onPropertyChnaged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

    }

ViewModel2

public class Data2 : INotifyPropertyChanged
    {
        private string _string2;

        public string String2
        {
            get { return _string2; }
            set { _string2 = value; onPropertyChnaged("String2");}
        }

        private void onPropertyChnaged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

    }

Views:

public partial class MainWindow : Window
    {
        Data12 d12 = new Data12 { };
        public MainWindow()
        {
            InitializeComponent();
            DataContext = d12;
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            ViewModel_1();
            ViewModel_2();
        }

        private void ViewModel_1()
        {
            var viewmodel = DataContext as Data12;
            viewmodel.Data1.String1 = textBox.Text;
        }
        private void ViewModel_2()
        {
            var viewmodel = DataContext as Data12;
            viewmodel.Data1.String1 = textBox.Text;
        }
}

Combined ViewModel:

class Data12
    {
        public Data1 Data1 = new Data1();
        public Data2 Data2= new Data2();
    }

Xaml file:

<Grid>

        <Label x:Name="label" HorizontalAlignment="Left" Margin="92,61,0,0" VerticalAlignment="Top" Content="{Binding Data1.String1}"  />

        <Label x:Name="label1" Content="{Binding Data2.String2}" HorizontalAlignment="Left" Margin="349,61,0,0" VerticalAlignment="Top" />
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="65,153,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="360,153,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="205,246,0,0" VerticalAlignment="Top" Width="75" Click="button_Click" />
</Grid>

There is no Nullreference, but binding is not working. I tried even by instantiating inner properties, but did not work. Please help me on this.

srinivas
  • 93
  • 3
  • 14
  • Why downgrade ? – srinivas Nov 02 '17 at 19:31
  • Where is `Data12`? – grek40 Nov 02 '17 at 19:31
  • 2
    Look at the output window for binding errors. WPF bindings are infamous for swallowing exceptions and errors and hiding them in the output window. – Alejandro Nov 02 '17 at 19:32
  • Sorry missed to adding sorry for that – srinivas Nov 02 '17 at 19:33
  • 4
    A good starting point for you: [Why does WPF support binding to properties of an object, but not fields?](https://stackoverflow.com/questions/842575/why-does-wpf-support-binding-to-properties-of-an-object-but-not-fields) – grek40 Nov 02 '17 at 19:35
  • Output: BindingExpression path error:'Data1' property not found on 'object' ''Data12' (HashCode=15767257)'. BindingExpression: Path =Data1.String1; DataItem ='Data12'(HashCode=15767257); target element is 'Label' (Name='label'); target property is 'Content' (type 'Object') – srinivas Nov 02 '17 at 19:40
  • Thank you so much on the link .. It is very useful .. :) – srinivas Nov 02 '17 at 19:46

1 Answers1

2

You can't bind on Fields, so just turn them into properties and it should work:

class Data12
{
    public Data12()
    {
        this.Data1 = new Data1();
        this.Data2 = new Data2();
    }
    public Data1 Data1 { get; private set; }
    public Data2 Data2 { get; private set; }
}

As @Clemens commented, this can be shortened to

class Data12
{
    public Data1 Data1 { get; } = new Data1();
    public Data2 Data2 { get; } = new Data2();
}
grek40
  • 13,113
  • 1
  • 24
  • 50
  • 1
    Please note that you could also write `public Data1 Data1 { get; } = new Data1();`, thus avoiding the need for a constructor. – Clemens Nov 03 '17 at 06:25
  • @Clemens thanks, I was considering it, but I'm stuck with VS 2012 (don't ask me why^^) and didn't want to provide untested code. – grek40 Nov 03 '17 at 06:30
  • what special you have done? i followed same way but my UI is not updating. – Ashish-BeJovial Dec 30 '19 at 17:54
  • @AshishJain if you want to update, you probably need to implement `INotifyPropertyChanged`. This question was written in a way, where pre-initialized readonly properties where sufficient. If you add a setter that's used anywhere outside of the constructor, add a property changed handling too. – grek40 Jan 01 '20 at 04:21