0
votes

I'm getting a strange behavior in a test model for mvvm-light: I created one Window and setted two resources, one grid with two distinct dataContext, the problem is that the two view models are receiving the response even if I'm using only the side of one dataContext. Is there a way to set only the specified data context to fire to the view model that I indicate?

XAML Code:

<Window x:Class="POCWPFValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:POCWPFValidation.ViewModel"
        Title="MainWindow" Height="350" Width="525" >
    <Window.Resources>
        <vm:MainViewModel x:Key="Main"/>
        <vm:SecondaryView x:Key="Sec"/>
    </Window.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal">
            <StackPanel Orientation="Vertical" DataContext="{Binding Source={StaticResource Main}}">
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox1Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox2Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox3Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox4Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <TextBox Text="{Binding StringTest, UpdateSourceTrigger=PropertyChanged}" />
                <Button Content="Button" Command="{Binding Teste}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
                <Button Content="Button" Command="{Binding Teste2}" CommandParameter="{Binding ElementName=TextBox1, Path=Text}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
            </StackPanel>

            <StackPanel Orientation="Vertical" DataContext="{Binding Source={StaticResource Sec}}">
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox1Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox2Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox3Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <CheckBox Content="CheckBox" IsChecked="{Binding CheckBox4Checked}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <TextBox Text="{Binding StringTest, UpdateSourceTrigger=PropertyChanged}" />
                <Button Content="Button" Command="{Binding Teste}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
                <Button Content="Button" Command="{Binding Teste2}" CommandParameter="{Binding ElementName=TextBox1, Path=Text}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="{x:Null}" DataContext="{Binding Mode=OneWay}"/>
            </StackPanel>
        </StackPanel>

    </Grid>
</Window>

The views are the same, so just change the name to SecondaryView

    namespace POCWPFValidation.ViewModel
    {
      public class MainViewModel : ViewModelBase
      {
          private bool m_blnCheckBox1Checked;
        private bool m_blnCheckBox2Checked;
        private bool m_blnCheckBox3Checked;
        private bool m_blnCheckBox4Checked;
        public bool CheckBox1Checked
        {
            get { return m_blnCheckBox1Checked; }
            set
            {
                Set(ref m_blnCheckBox1Checked, value, true);
            }
        }
        public bool CheckBox2Checked
        {
            get { return m_blnCheckBox2Checked; }
            set
            {
                Set(ref m_blnCheckBox2Checked, value, true);
            }
        }
        public bool CheckBox3Checked
        {
            get { return m_blnCheckBox3Checked; }
            set
            {
                Set(ref m_blnCheckBox3Checked, value, true);
            }
        }
        public bool CheckBox4Checked
        {
            get { return m_blnCheckBox4Checked; }
            set
            {
                Set(ref m_blnCheckBox4Checked, value, true);
            }
        }

        string m_strStringTest = string.Empty;
        public string StringTest
        {
            get { return m_strStringTest; }
            set
            {
                Set(ref m_strStringTest, value, true);
            }
        }

        public RelayCommand<string> Teste2 { get; private set; }

        public RelayCommand Teste { get; private set; }

        public MainViewModel()
        {
            Teste = new RelayCommand(MyAction, MyCanExecute);
            Teste2 = new RelayCommand<string>(MyAction2, MyCanExecute2);
        }

        private void MyAction()
        {


        }
        private void MyAction2(string seila)
        {

        }

        private bool MyCanExecute2(string teste)
        {
            return !string.IsNullOrWhiteSpace(teste);            

        }

        private bool MyCanExecute()
        {
            if (CheckBox1Checked && CheckBox2Checked && CheckBox3Checked && CheckBox4Checked && StringTest.Equals("teste"))
            {
                return true;
            }
            return false;
        }
    }
}

EDIT:

Sorry, I was not clear with my question, let me try again: like I told before, I have two view models and two distinct datacontext in mainWindow one for each viewmodel. Every time some property on any of these view models changes all the canExecute method of the two viewmodels are triggered. Change some property on view A and the can execute will be triggered on views A and B. Is there a way to only trigger at the specific CanExecute responsible view?

1
Set(ref m_strStringTest, value, true); is not a method provided by MVVM's ViewModelBase class (it is missing the property name argument). Aside from that, i tested the code from your question and i cannot reproduce your problem (i.e., the checkboxes in the first stackpanel only bind against and update the properties of the "Main" VM, and the checkboxes of the second stackpanel only work with/on the "Sec" VM. Thus, whatever your problem, it is not caused by the code in your question... - user2819245
Sorry, I was not clear with my question, let me try again: like I told before, I have two view models and two distinct datacontext in mainWindow one for each viewmodel. Every time some property on any of these view models changes all the canExecute method of the two viewmodels are triggered. Change some property on view A and the can execute will be triggered on views A and B. Is there a way to only trigger at the specific CanExecute responsible view? - Lucas Gazire

1 Answers

0
votes

CanExecute is not triggered by the property changes but by CommandManager.RequerySuggested event. Don't worry about when its invoked WPF handles that