Syeman
Syeman

Reputation: 67

Passing data between two usercontrols / Views

Using MVVM

I am trying to pass data entered in a control (a textbox in the attached code) in one view (view1) and use that data in the second view (view2). At the moment, by declaring all my views in the App.xaml file, I can bind the textblock in view2 with the information entered in the textbox in view1 and see it displayed in the said textblock. But I want to use the information entered in view2's view model as well but dont know how to access it there to use the information.

Can somebody tell me how to go about doing this? Thanks!

App.xaml [declaration of resources]

<Application.Resources>
<vws:DefaultVM x:Key="DefaultVMApp"></vws:DefaultVM>
<vws:View1 x:Key="View1App"></vws:View1>
<vws:View2 x:Key="View2App"></vws:View2>
<vm:AppVM x:Key="AppVMApp"></vm:AppVM>
<vm:View1VM x:Key="View1VMApp"></vm:View1VM>
<vm:View2VM x:Key="View2VMApp"></vm:View2VM>
</Application.Resources>

View1.xaml

    <UserControl.DataContext>
    <StaticResource ResourceKey="View1VMApp"></StaticResource>
    </UserControl.DataContext>
    <Grid Background="Aqua">
    <StackPanel Margin="100">
    <TextBox x:Name="firstNameTextBoxView1" Text="{Binding View1InfoClass.FirstName, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>           
    <Button Command="{Binding Source={StaticResource AppVMApp}, Path=View2ButtonCommand}"  Content="Go to view2" Height="20" Width="70" />
    </StackPanel>
</Grid>

View2.xaml

<UserControl.DataContext>
        <StaticResource ResourceKey="View2VMApp"></StaticResource>
    </UserControl.DataContext>
    <Grid Background="Beige">
        <StackPanel Margin="100">

            <TextBlock x:Name="View1TextBlock" Text="{Binding Source={StaticResource View1VMApp}, Path=View1InfoClass.FirstName}" ></TextBlock>

        </StackPanel>
    </Grid>

AppVM

    public class AppVM : ObservableObject
        {
            //Create a property that controls current view
            private static object _currentView =  new DefaultVM();
            public object CurrentView
            {
                get { return _currentView; }
                private set
                {
                    OnPropertyChanged(ref _currentView, value);
                }
            }
            private string _textboxText;
            public string TextboxText
            {
                get { return _textboxText; }
                set
                {
                    OnPropertyChanged(ref _textboxText, value);
                }
            }
            public AppVM()
            {
                View1ButtonCommand = new RelayCommand(ShowView1, AlwaysTrueCommand);
                View2ButtonCommand = new RelayCommand(ShowView2, AlwaysTrueCommand);
                DefaultCommand = new RelayCommand(ShowDefault, AlwaysTrueCommand);  
            }
//Instantiate the relaycommands, we will need to instantiate relaycommand objects for every command we need to perform. 
            //This means that we will need to do this for preses of all buttons
            public RelayCommand View1ButtonCommand { get; private set; }
            public RelayCommand View2ButtonCommand { get; private set; }

            public RelayCommand DefaultCommand { get; private set; }


            public void ShowDefault(object dummy)
            {
                CurrentView = new DefaultVM();
            }

            public void ShowView1(object dummy)
            {
                CurrentView = new View1();
            }

            public void ShowView2(object dummy)
            {  
                CurrentView =  new View2();
            }

            public bool AlwaysTrueCommand(object dummy)
            {
                return true;
            }
        }

View1 and View2 layout, kind of TLDR

Upvotes: 2

Views: 574

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70671

The fundamental problem in your code is that you have dedicated a pre-defined view model object to each of the user controls. This is really bad. A user control's data context must be left alone, for the client code (e.g. your main window) to determine, and to use for binding to specific properties that the user control exposes.

Unfortunately, there's not enough context in your question to provide a clear, complete answer. But to fix your issue, you need to do things differently:

  1. First and foremost, "decouple" the view models you are using for your user control from the user controls themselves. Do this by adding dependency properties to each user control, and then letting the main view where the user controls are used decide what to bind to each of those dependency properties. Do not allow the user controls themselves to set their own data contexts.
  2. Having done that, you may find that you can just use the same view model for the two user controls as for the main view. I.e. you'll set the main view's data context to the single view model, the user controls will inherit that data context, and you'll bind, for example, the TextboxText property to the appropriate declared dependency property in each user control. This way, that single property will represent state for both user controls at the same time.

One hopes that will be enough to get you back on track. If not, consider searching Stack Overflow for other questions related to view models and their relationships to user controls. For example, these questions:
Issue with DependencyProperty binding
XAML binding not working on dependency property?
WPF DataBinding with MVVM and User Controls

Other questions which don't address your scenario exactly, but which should give you some ideas for alternative ways to structure your view model(s):
MVVM : Share data between ViewModels
Sharing non control related data between WPF ViewModel and UserControl
Sharing data between different ViewModels
Sharing state between ViewModels

Upvotes: 2

Related Questions