I have two radio buttons in a group as part of my XAML project:
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Orientation="Horizontal" Grid.Column="0" Margin="20,0,0,0">
<RadioButton x:Name="XMLViewButton" GroupName="DisplayType" IsChecked="{Binding XmlViewIsChecked, FallbackValue=True, Mode=TwoWay}" Content="XML View" Margin="0,0,5,0"/>
<RadioButton x:Name="TextViewButton" GroupName="DisplayType" IsChecked="{Binding TextViewIsChecked, FallbackValue=False, Mode=TwoWay}" Content="Text View" Margin="5,0,0,0"/>
</StackPanel>
And I then have a command later on which refers to these IsChecked bindings:
public void CopyToClipboard(object o)
{
if (TextViewIsSelected == true)
{
Clipboard.SetText(myFile.TextContent);
}
else if (XmlViewIsSelected == true)
{
Clipboard.SetText(myFile.XMLContent);
}
}
However, the XmlViewIsSelected is permanently True and TextViewIsSelected is always false, no matter which radio button is selected. What am I missing?
I think you are mispelling XmlViewIsChecked with XmlViewIsSelected
The following for me is working
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Orientation="Horizontal" Grid.Column="0" Margin="20,0,0,0">
<RadioButton x:Name="XMLViewButton" GroupName="DisplayType" IsChecked="{Binding XmlViewIsChecked, FallbackValue=True, Mode=TwoWay}" Content="XML View" Margin="0,0,5,0"/>
<RadioButton x:Name="TextViewButton" GroupName="DisplayType" IsChecked="{Binding TextViewIsChecked, FallbackValue=False, Mode=TwoWay}" Content="Text View" Margin="5,0,0,0"/>
<Button Content="Check" Click="Button_Click" />
</StackPanel>
public partial class MainWindow : Window
{
public bool XmlViewIsChecked { get; set; }
public bool TextViewIsChecked { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (TextViewIsChecked)
{
Clipboard.SetText("text");
}
else if (XmlViewIsChecked)
{
Clipboard.SetText("xml");
}
}
}
Related
I have a datagrid which holds the User information. Now once, I click on the selected row, I want to display the user information such as their roles and allow the user to edit the user roles by clicking on the combobox. Under my data template I have the combobox in my xaml. Since using the datatemplate, the combobox name couldnt be found, I am using the following method below to get the children from the grid.
Here is the code to get the children element:
private List<FrameworkElement> GetChildren(DependencyObject parent)
{
List<FrameworkElement> controls = new List<FrameworkElement>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); ++i)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is FrameworkElement)
{
controls.Add(child as FrameworkElement);
}
controls.AddRange(GetChildren(child));
}
return controls;
}
I created the selection changed event for the datagrid:
private void userDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var userRolesList = new User().getUserRoles();
ComboBox cbUserRole = (ComboBox)GetChildren(userDataGrid).First(x => x.Name == "cbUserRole");
cbUserRole.ItemsSource = userRolesList;
}
Now when I run this code, I am being shown error message
Sequence contains no matching element
The same method I use for my textboxes, I am able to display the values and edit the values too. But for my combobox its not working the way it supposed to. Can someone please help me on this. Thanks.
This is my xaml code:
<DataGrid AutoGenerateColumns="False" Grid.Row="2" Grid.ColumnSpan="4" Grid.RowSpan="3" x:Name="userDataGrid" Margin="70,0.2,70,0" ItemsSource="{Binding}" SelectionChanged="userDataGrid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding UserId}"/>
<DataGridTextColumn Header="Username" Binding="{Binding UserName}"/>
<DataGridTextColumn Header="Email" Binding="{Binding UserEmail}"/>
<DataGridTextColumn Header="User Role" Binding="{Binding UserRole}"/>
<DataGridTextColumn Header="Created Date" Binding="{Binding UserCreatedDate}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="BlanchedAlmond" Padding="10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="User ID: " VerticalAlignment="Center" />
<TextBlock x:Name="txtBlockId" FontSize="16" Foreground="MidnightBlue" Text="{Binding UserId, Mode=TwoWay}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="First Name: " VerticalAlignment="Center" />
<TextBox x:Name="txtFirstName" FontSize="16" Foreground="MidnightBlue" Text="{Binding UserFirstName, Mode=TwoWay}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="Last Name: " VerticalAlignment="Center" />
<TextBox x:Name="txtLastName" FontSize="16" Foreground="MidnightBlue" Text="{Binding UserLastName}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="User Role: " VerticalAlignment="Center" />
<ComboBox x:Name="cbUserRole" FlowDirection="LeftToRight" FontSize="16" Foreground="MidnightBlue" HorizontalAlignment="Stretch" VerticalAlignment="Center" SelectionChanged="cbUserRole_Click"/>
</StackPanel>
<StackPanel>
<Button x:Name="btnUpdate" Content="Update" VerticalAlignment="Center" HorizontalAlignment="Right" Click="btnUpdate_Click"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Thanks
I've been seeing you asking around how to work with this, let me show you one way, hope this helps, but I recommend you read about MVVM patterns and frameworks like MVVMLight for WPF.
Well, for this, first you need to install Install-Package MvvmLight -Version 5.4.1
Then you may need to fix one reference issue, in the ViewModelLocator, remove all the usings and replace with:
using GalaSoft.MvvmLight.Ioc;
using CommonServiceLocator;
Now, your MainWindowView.xaml, it should like:
<Window x:Class="WpfApp2.MainWindow"
x:Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:WpfApp2.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel x:Name="Model"/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DataGrid AutoGenerateColumns="False" x:Name="userDataGrid" Margin="70,0.2,70,0" ItemsSource="{Binding Users}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding UserId}"/>
<DataGridTextColumn Header="Username" Binding="{Binding UserName}"/>
<DataGridTextColumn Header="Email" Binding="{Binding UserEmail}"/>
<DataGridTextColumn Header="User Role" Binding="{Binding UserRole}"/>
<DataGridTextColumn Header="Created Date" Binding="{Binding UserCreatedDate}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="BlanchedAlmond" Padding="10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="User ID: " VerticalAlignment="Center" />
<TextBlock x:Name="txtBlockId" FontSize="16" Foreground="MidnightBlue" Text="{Binding UserId, Mode=TwoWay}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="First Name: " VerticalAlignment="Center" />
<TextBox x:Name="txtFirstName" FontSize="16" Foreground="MidnightBlue" Text="{Binding UserFirstName, Mode=TwoWay}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="Last Name: " VerticalAlignment="Center" />
<TextBox x:Name="txtLastName" FontSize="16" Foreground="MidnightBlue" Text="{Binding UserLastName}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="User Role: " VerticalAlignment="Center" />
<ComboBox ItemsSource="{Binding Path=DataContext.UserRoles, ElementName=root}" SelectionChanged='CbUserRole_OnSelectionChanged' SelectedItem="{Binding UserRole}" x:Name="cbUserRole" FlowDirection="LeftToRight" FontSize="16" Foreground="MidnightBlue" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
</StackPanel>
<StackPanel>
<Button x:Name="btnUpdate" Content="Update" VerticalAlignment="Center" HorizontalAlignment="Right" Command="{Binding UpdateCommand, ElementName=Model}" CommandParameter="{Binding}" />
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
Then in your code-behind, there's a little event handling that needs to be done, when changing the roles,
using System.Windows;
using System.Windows.Controls;
using WpfApp2.ViewModel;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public MainViewModel ViewModel => (MainViewModel) DataContext;
private void CbUserRole_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (cb != null)
{
ViewModel.SelectedUserRole = (UserRole)cb.SelectedItem;
}
}
}
}
Then you should create a ViewModel like so (ViewModel -> MainViewModel.cs):
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using GalaSoft.MvvmLight.Command;
using WpfApp2.Data;
namespace WpfApp2.ViewModel
{
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
PopulateUserTestData();
UpdateCommand = new RelayCommand<User>(UpdateUser);
}
private ObservableCollection<User> _users;
public ObservableCollection<User> Users
{
get => _users;
set
{
if (_users != value)
{
_users = value;
NotifyPropertyChanged();
}
}
}
private UserRole _userRole;
public UserRole SelectedUserRole
{
get => _userRole;
set
{
if (_userRole != value)
{
_userRole = value;
NotifyPropertyChanged();
}
}
}
public RelayCommand<User> UpdateCommand { get; }
public IEnumerable<UserRole> UserRoles => Enum.GetValues(typeof(UserRole)).Cast<UserRole>();
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void UpdateUser(User user)
{
Users.Single(u => u.UserId == user.UserId).UserRole = SelectedUserRole;
// Do updates on your context (or in-memory).
PrintUsersOnDebug();
}
#region Test data and diagnostics support
private void PrintUsersOnDebug()
{
foreach (User user in Users)
{
Debug.WriteLine("Username: " + user.UserName + " Role: " + user.UserRole);
}
}
private void PopulateUserTestData()
{
Users = new ObservableCollection<User>
{
new User
{
UserId = 1,
UserCreatedDate = DateTime.Now,
UserEmail = "johndoe1#email.com",
UserFirstName = "John",
UserLastName = "Doe",
UserName = "johnd",
UserRole = UserRole.Administrator
},
new User
{
UserId = 2,
UserCreatedDate = DateTime.Now,
UserEmail = "billgordon#email.com",
UserFirstName = "Bill",
UserLastName = "Gordon",
UserName = "billg",
UserRole = UserRole.SuperUser
}
};
PrintUsersOnDebug();
}
#endregion
}
}
Other related classes:
Data->User.cs
using System;
namespace WpfApp2.Data
{
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
public string UserEmail { get; set; }
public UserRole UserRole { get; set; }
public DateTime UserCreatedDate { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
}
}
UserRole.cs
namespace WpfApp2
{
public enum UserRole
{
Administrator,
User,
SuperUser
}
}
Now since I just designed this test app to view the changing data in this case roles, I designed this to be just viewable on output window. As you change the roles and click the update button, inspect the output window.
If you simply want to populate the ComboBox in the RowDetailsTemplate, you could handle its Loaded event:
private void cbUserRole_Loaded(object sender, RoutedEventArgs e)
{
ComboBox cbUserRole = (ComboBox)sender;
if (cbUserRole.ItemsSource == null)
cbUserRole.ItemsSource = new User().getUserRoles();
}
XAML:
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="User Role: " VerticalAlignment="Center" />
<ComboBox x:Name="cbUserRole"
Loaded="cbUserRole_Loaded"
FlowDirection="LeftToRight" FontSize="16" Foreground="MidnightBlue" HorizontalAlignment="Stretch"
VerticalAlignment="Center"
SelectionChanged="cbUserRole_Click"/>
</StackPanel>
I created datatemplate for my listview with 2 button that must user click on if i use my datatemplate in Window everything's is OK and work fine but if I use my datatemplate in Usercontrol click event for my buttons not work so what is the problem? this is my codes:
<ListView Name="lvDataBinding" HorizontalContentAlignment="Stretch" BorderThickness="0" Margin="10" Grid.Row="3" Background="{x:Null}" SelectionChanged="lvDataBinding_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="#f0f4f7">
<StackPanel Background="#f5f6fa" Margin="1,1,1,1" VerticalAlignment="Top">
<Border Background="#edf0f5" BorderThickness="5">
<Grid Background="#ffffff" Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Background="#ffffff" Margin="5" Orientation="Horizontal">
<Button Height="20" Width="20" BorderBrush="Transparent" BorderThickness="0" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.cmddelete}">
<Button.Background>
<ImageBrush ImageSource="E:\Aks\ICON\colorful-stickers-icons-set\png\32x32\accept.png"/>
</Button.Background>
</Button>
<Button Height="20" Width="20" BorderBrush="Transparent" BorderThickness="0" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.cmdShow}">
<Button.Background>
<ImageBrush ImageSource="E:\Aks\ICON\colorful-stickers-icons-set\png\32x32\accept.png"/>
</Button.Background>
</Button>
</StackPanel>
<TextBlock Name="txtPhon" Foreground="#7c7f84" HorizontalAlignment="Right" Grid.Column="1" Text="{Binding Path=HomePhoneNumber}"
Margin="0,5,5,5"/>
</Grid>
</Border>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And this is my code behind that I created iCommand and bind it to buttons :
public ICommand cmdShow { get; set; }
public ICommand cmddelete { get; set; }
private FrameworkElement Window { get; set; }
int index = 0;
public UserControl1()
{
InitializeComponent();
InitalizeData();
this.DataContext = this;
Window = this;
cmdShow = new RoutedCommand();
cmddelete = new RoutedCommand();
CommandManager.RegisterClassCommandBinding(Window.GetType(), new CommandBinding(cmdShow, cmdShow_Click));
CommandManager.RegisterClassCommandBinding(Window.GetType(), new CommandBinding(cmddelete, cmddelete_Click));
}
protected void cmdShow_Click(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show(lvDataBinding.SelectedIndex + "");
}
protected void cmddelete_Click(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("delete");
}
private void InitalizeData()
{
ObservableCollection<Patient> data = new ObservableCollection<Patient>();
for (int i = 0; i < 3; i++)
{
data.Add(new Patient
{
HomePhoneNumber = "0512-62810609"
});
}
this.lvDataBinding.ItemsSource = data;
}
public class Patient
{
public string HomePhoneNumber { get; set; }
}
Depending where you set the DataContext the Problem is probably caused by
AncestorType={x:Type **Window**}}
I need to bind the text box with the data available on it and execute a command associate with that. I want the data entered as well command execution only when "Enter" button on keyboard is pressed. I used to the below code, but it seems, I am getting command execution without "Enter" is pressed also found that for each number or text pressed, I am getting the command. I don't want this to happen.
my InputDataTemplate.xaml code:
<Label Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Content="{Binding Name}" />
<Label Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Content="{Binding Value}" />
<TextBox Grid.Column="1" Width="60" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Data}" DataContext="{Binding}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged" >
<ei:CallMethodAction TargetObject="{Binding}" MethodName="IpDataTrig" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
I can understand EventName="TextChanged" plays a role here. But not sure about the other stuffs.
My TesterView.xaml code:
<UserControl.Resources>
<DataTemplate x:Key="InputDataTemplate" >
<local:InputDataTemplate DataContext="{Binding}" />
</DataTemplate>
</UserControl.Resources>
<Grid Grid.Row="2" Background="AliceBlue" >
<Label Content="Input Datas" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<Border Grid.Row="3" BorderBrush="Black" BorderThickness="0,2,0,0" >
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" >
<ItemsControl x:Name="IpDataNames"
DataContext="{Binding }"
ItemsSource="{Binding IpDataNames}"
ItemTemplate="{DynamicResource InputDataTemplate}" />
</ScrollViewer>
</Border>
my TesterViewModel.cs:
private ObservableCollection<InputDataService> _IpDataNames;
private InputDataService l_IpDataNames;
_IpDataNames = new ObservableCollection<InputDataService>();
public ObservableCollection<InputDataService> IpDataNames
{
get { return _IpDataNames; }
set
{
IpDataNames = value;
}
}
InputDataService.cs:
public class InputDataService : BindableBase
{
public string Name { get; set; }
public string Value { get; set; }
public string Data { get; set; }
public void IpDataTrig()
{
Debug.WriteLine(string.Format("\nInput Data {0} Updated : {1} : {2}", Name, Data, Value));
}
}
Possible duplicate question: https://stackoverflow.com/a/10466285/475727
BTW, nothing is wrong about capturing KeyPress event and calling command from codebehind. It is not violation of MVVM pattern.
Sometimes I use my own behavior implemented as attached property. Big advantage is, that I can use it in styles.
This behaviour update binding source on text property and then calls command. (TextBox.Text binding is updated on losf focus by default)
public static class TextBoxBehaviour
{
public static readonly DependencyProperty CommandOnEnterPressedProperty = DependencyProperty.RegisterAttached("CommandOnEnterPressed",typeof (ICommand),typeof (TextBoxBehaviour),
new FrameworkPropertyMetadata(CommandOnEnterPressedPropertyChanged));
private static void CommandOnEnterPressedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = (TextBox) d;
sender.KeyDown -= OnKeyDown;
if (e.NewValue is ICommand)
{
sender.KeyDown += OnKeyDown;
}
}
private static void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
var tbx = (TextBox) sender;
var textBindigExpression = tbx.GetBindingExpression(TextBox.TextProperty);
if (textBindigExpression != null)
{
textBindigExpression.UpdateSource();
}
var command = GetCommandOnEnterPressed(tbx);
if (command.CanExecute(null)) command.Execute(null);
}
}
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static void SetCommandOnEnterPressed(TextBox elementName, ICommand value)
{
elementName.SetValue(CommandOnEnterPressedProperty, value);
}
public static ICommand GetCommandOnEnterPressed(TextBox elementName)
{
return (ICommand) elementName.GetValue(CommandOnEnterPressedProperty);
}
}
and usage
<TextBox Text="{Binding SearchTerm, UpdateSourceTrigger=Explicit}"
my:TextBoxBehaviour.CommandOnEnterPressed="{Binding SearchCommand}"/>
With a checkbox I want to enable or disable a datepicker, but my code doesn't work.
This is the xaml
<CheckBox HorizontalAlignment="Left" Height="32"
IsChecked="{Binding ABC}"
Margin="108,91,0,0" VerticalAlignment="Top" Width="191"/>
<DatePicker HorizontalAlignment="Left" Height="32"
IsEnabled="{Binding ABC}"
Margin="142,91,0,0" VerticalAlignment="Top" Width="217"/>
And this is the property.
private bool _ABC {
get;
set;
}
public bool ABC {
get {
return _ABC;
}
set {
_ABC = value;
}
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
MainWindow Vm = new MainWindow();
this.DataContext = Vm;
ABC = false;
}
Thank you
You need to tell it what property it's looking for, and who to get it from, like;
<CheckBox x:Name="TheCheckBox"
HorizontalAlignment="Left" Height="32"
IsChecked="{Binding ABC}"
Margin="108,91,0,0" VerticalAlignment="Top" Width="191"/>
<DatePicker HorizontalAlignment="Left" Height="32"
IsEnabled="{Binding IsChecked, ElementName=TheCheckBox}"
Margin="142,91,0,0" VerticalAlignment="Top" Width="217"/>
Hope this helps, cheers.
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?
CanExecute is not triggered by the property changes but by CommandManager.RequerySuggested event. Don't worry about when its invoked WPF handles that