question

MERUNKUMARMAITY-4120 avatar image
0 Votes"
MERUNKUMARMAITY-4120 asked MERUNKUMARMAITY-4120 commented

How to declare multiple viewmodels as static resource in a datacontext of a Grid in WPF?

I have a WPF application where I use multiple view models. Sometimes I use the same view model multiple times, though I have some other different type of view models. My main question is, how can I declare multiple view models as a single data context in one Grid.

Here is the code of one of my view model :

 using System.ComponentModel;
      using System.Windows;
      namespace TabControlBindSlide
      {
        public partial class MainWindow : Window
        {
          public MainWindow()
          {
            InitializeComponent();
          }
        }
        class TestViewModel : INotifyPropertyChanged
        {
          private int _selected;
          public int Selected
          {
            get { return _selected; }
            set
            {
              int temp = _selected;
              _selected = value;
              _previousSelected = temp;
              NotifyPropertyChanged("Selected", temp, value);
              NotifyPropertyChanged("PreviousSelected", temp, temp);
            }
          }
          int _previousSelected = 0;
          public int PreviousSelected
          {
            get { return _previousSelected; }
          }
          public event PropertyChangedEventHandler PropertyChanged;
          protected void NotifyPropertyChanged<T>(string propertyName, T oldvalue, T newvalue)
          {
            OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(propertyName, oldvalue, newvalue));
          }
          public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
          {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
              handler(sender, e);
          }
        }
        public class PropertyChangedExtendedEventArgs<T> : PropertyChangedEventArgs
        {
          public virtual T OldValue { get; private set; }
          public virtual T NewValue { get; private set; }
        
      public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue)
          : base(propertyName)
      {
        OldValue = oldValue;
        NewValue = newValue;
      }
    }
  }

And I use this in my Grid as a static resource of a data context.

Here is my MainWindow.xaml code :

  <Grid  DataContext="{StaticResource vm}" >
          <Grid.RowDefinitions>
              <RowDefinition Height="*"/>
              <RowDefinition Height="50"/>
          </Grid.RowDefinitions>
          <TabControl     SelectedIndex="{Binding Selected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"     Grid.Row="0"   x:Name="TestTabs">
              <TabItem Name="Tab1" Header="News" />
              <TabItem Name="Tab2" Header="DLC" />
              <TabItem Name="Tab3" Header="Settings"/>
          </TabControl>
          <DockPanel  x:Name="rp" Grid.Row="0" LastChildFill="False" HorizontalAlignment="Stretch">
              <Canvas DockPanel.Dock="Left" >
                  <Rectangle x:Name="Rect1" Fill="#ff0000" VerticalAlignment="Top"  Height="4" Margin="0,25,0,0" 
                             SnapsToDevicePixels="True" UseLayoutRounding="True" RenderOptions.EdgeMode="Aliased" 
                             Width="{Binding ElementName=TestTabs, Path=SelectedItem.ActualWidth}"  RenderOptions.BitmapScalingMode="HighQuality" />
              </Canvas>
          </DockPanel>
          <StackPanel Orientation="Horizontal" Grid.Row="1">
              <Label Content="selected" Width="100" Height="40" />
              <TextBox x:Name="sele" Text="{Binding Selected}" Width="100" Height="40" Background="AliceBlue" Margin="5"/>
              <Label Content="previousSelected"  Width="100" Height="40"/>
              <TextBox x:Name="prev" Text="{Binding PreviousSelected,Mode=OneWay}" Width="100" Height="40" Background="AliceBlue" Margin="5"/>
          </StackPanel>
      </Grid>

If you look the code carefully, then you see that the Grid has only one data context as static resource which is a view model name VM. This line <Grid DataContext="{StaticResource vm}" >. How I declare more view models in that Grid because this is my main Grid, and as the application became more mature the more features will be added into it, thus the application will get more complexity. Complex application have lot of view models involved.

I also try to declare the view model as a static resource in the data context of a Dock panel but it does not working. I still don't know that how the view model so tied up with the Grid?

dotnet-csharpwindows-wpf
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi,@MERUNKUMARMAITY-4120. You could bind multiple ViewModels for different controls in a view. You can refer to Option 1 and Option 2. Please let me know if there are any questions.


1 Vote 1 ·

Thank you very much sir, as usual you are always present to help me in my difficult situation. Your Option 1 and Option 2 examples are above my head and I don't understand anything from it. If you kindly give your own answer. I assume that you don't properly understand what I want to achieve. I again told you in simple sentences. Suppose I have two view models one is V1 and another is V2. I have one main Grid and I want to declare these two view models as a Data context in that main Grid. I already give the view model code now for this purpose please consider that both V1 and V2 use the same code. How I declare those two In one Main Grid?

<Grid DataContext="{StaticResource V1}" > this is one way to declare a view model in the main Grid, in this case I declare V1. now the question is how I declare the V2 view model in same way that means I want both as data context. The code should be <Grid DataContext="{StaticResource V1}" + "{StaticResource V2}">. I know this code is completely wrong but I just told the behind logic that what I want achieve.

Please give your complete code as answer. Use my code from the question and modify your answer according to my code, I don't understand code example from Stack overflow. Give your code answer in brief with proper explanations.

I am ready to accept your answer.

By the way, you are my best coding teacher.

0 Votes 0 ·

1 Answer

HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered MERUNKUMARMAITY-4120 commented

You could bind different DataContexts to different controls.

A control cannot be bound to multiple different DataContexts. ( A control can only have one object set to its DataContext property.) For more information, you could refer here.

However, the binding does not have to be bound to its DataContext. You can use other binding properties to specify a different source for the binding. Common properties for changing binding sources are Source, RelativeSource, and ElementName. You can refer here for more details.

  • You can only change the binding source for a specific binding, like you did in the Command binding.

  • Alternatively, you can change it for the entire control by setting or binding the control's DataContext property to something else.

MainWindow.xaml:

      <Window.Resources>
             <local:MainViewModel x:Key="mvm"/>
         </Window.Resources>
         <Grid DataContext="{StaticResource mvm}" >
             <Grid.RowDefinitions>
                 <RowDefinition/>
                 <RowDefinition/>
             </Grid.RowDefinitions>
             <Grid  x:Name="grid1" Background="AliceBlue" Height="100" DataContext="{Binding VM1}" >
                 <TextBlock VerticalAlignment="Top" Foreground="Black" Background="White" HorizontalAlignment="Left" Text="{Binding String1}" Width="100" Height="40">
                     <TextBlock.ToolTip>
                         <!--<TextBlock  Background="White" Foreground="Black"  Width="100" Height="40" Text="{Binding ElementName=tb,Path= Text}"/>-->
                         <TextBlock>
                             <Run Text="{Binding Source={x:Reference tb}, Path=Text}" FontWeight="Bold"/>
                         </TextBlock>
                     </TextBlock.ToolTip>
                 </TextBlock>
                 <TextBlock  Background="White" Foreground="Black"  Width="100" Height="40" Text="{Binding ElementName=tb,Path=DataContext.String2}"/>
             </Grid>
             <Grid x:Name="grid2"  Grid.Row="1" Background="LightGreen"  Height="100" DataContext="{Binding VM2}">
                 <TextBlock x:Name="tb" VerticalAlignment="Top" Foreground="Black"  Background="White" HorizontalAlignment="Left" Text="{Binding String2}" Width="100" Height="40"/>
             </Grid>
         </Grid>

MainWindow.xaml.cs:

  public partial class MainWindow : Window
   {
     public MainWindow()
     {
       InitializeComponent();
     }
   }
   public class MainViewModel
   {
     public ViewModel1 VM1{ get; set; }
     public ViewModel2 VM2 { get; set; }
     public MainViewModel()
     {
       VM1=new ViewModel1();
       VM2=new ViewModel2();
     }
   }
   public class ViewModel1 
   {
     public string String1 { get;set;} ="string1";
   }
   public class ViewModel2 
   {
     public string String2 { get;set;}="string2";
   }

The result:
203536-image.png


If the response is helpful, please click "Accept Answer" and upvote it.
 Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread. 


image.png (8.6 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you very much sir for your brief explanation, this is the answer I always wanted from you. Brilliant you are. I almost ready to accept your answer, But my one last question is suppose I have only one view model and I want to use this view model on different controls multiple times. Can I use that view model multiple times by just declaring once as a static resource in the data context of the main Grid? And if possible then please tell me the logic behind of main Grid data context, that means why I need to declare in the main Grid always instead of another parent Grid where the rectangle belongs to.

0 Votes 0 ·
HuiLiu-MSFT avatar image HuiLiu-MSFT MERUNKUMARMAITY-4120 ·

hI, @MERUNKUMARMAITY-4120 . You could bind DataContext in MainGrid.
See FrameworkElement.DataContext Property:

Data context is a concept that allows elements to inherit information from their parent elements about the data source that is used for binding, as well as other characteristics of the binding, such as the path.

Quoted from How to: Specify a Binding Source

If you are binding several properties to a common source, you want to use the DataContext property, which provides a convenient way to establish a scope within which all data-bound properties inherit a common source.

1 Vote 1 ·

Thank your very much sir, to clear my concepts. I accepted your answer kindly check it. I shall reach out to you again if I face any type of difficulties in coding.

0 Votes 0 ·