I am trying to work on DevExpress GridControl Checkbox column but problem is that when I binding the checkbox value in XAML code dynamically its not work perfectlly
below I provide you my demo project code :-
XAML Code:-
<dxg:GridControl AutoPopulateColumns="True" HorizontalAlignment="Left" Margin="0,40,0,0" Name="gridControl1" VerticalAlignment="Top" Height="318" Width="503">
<dxg:GridControl.View>
<dxg:TableView Name="tableView1" ShowTotalSummary="True" />
</dxg:GridControl.View>
<dxg:GridControl.Columns>
<dxg:GridColumn DisplayMemberBinding="{Binding Path=EvenOdd}" Header="Even/Odd" />
<dxg:GridColumn Name="PickColumn" Header="Pick" Width="30"
AllowColumnFiltering="False" AllowSorting="False">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsValid}"
HorizontalAlignment="Center" VerticalAlignment="Center" >
</CheckBox>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
</dxg:GridControl.Columns>
</dxg:GridControl>
my cs file code:-
public class ss
{
public bool IsValid { get; set; }
public string EvenOdd { get; set; }
}
Code Behind:
public List<ss> sList = new List<ss>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
sList.Add(new ss { IsValid = true, EvenOdd = "Even" });
}
else
{
sList.Add(new ss { IsValid = false, EvenOdd = "Odd" });
}
}
gridControl1.ItemsSource = sList;
}
Adding on to HighCore's answer. If you would like to edit the data in your grid.
See ColumnBase.CellTemplate Property:
To enable data editing, use an editor shipped with the DevExpress Data Editors Library for WPF. The editor's Name must be set to
'PART_Editor'.
Standard controls can be used in CellTemplate only for display purposes. Data editing is not allowed.
Then,
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
<dxg:GridColumn Name="PickColumn"
Header="Pick"
Width="30"
AllowColumnFiltering="False"
AllowSorting="False">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<dxe:CheckEdit x:Name="PART_Editor"
EditValue="{Binding Path=Data.IsValid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
You still need to use HighCore's implementation of INotifyPropertyChanged.
First of all you need to correct the binding inside the CellTemplate:
<CheckBox IsChecked="{Binding Path=RowData.Row.IsValid}"/>
Second, your data items should implement INotifyPropertyChanged:
public class ss:INotifyPropertyChanged
{
private bool _isValid;
private string _evenOdd;
public bool IsValid
{
get { return _isValid; }
set
{
_isValid = value;
OnPropertyChanged("IsValid");
}
}
public string EvenOdd
{
get { return _evenOdd; }
set
{
_evenOdd = value;
OnPropertyChanged("EvenOdd");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
xmlns:dxgcore="http://schemas.devexpress.com/winfx/2008/xaml/grid"
<dxgcore:GridColumn Width="20"
AllowEditing="True"
Binding="{Binding Path=IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Header="R"
Visible="{Binding CheckboxSelection}"
VisibleIndex="6">
<dxgcore:GridColumn.CellTemplate>
<DataTemplate>
<dxe:CheckEdit HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding
Path=View.DataContext.IsCheckedCommand}"
CommandParameter="{Binding RowData.Row}"
IsChecked="{Binding RowData.Row.IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=View.DataContext.IsCheckBoxEnabled, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</dxgcore:GridColumn.CellTemplate>
</dxgcore:GridColumn>
And Notifychanged property
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}
Related
I am Building a WPF form in which I want to achieve a cascading dropdown inside an ItemsControl. There would be multiple rows and Dropdown2 source is dependent on Dropdown1.
The row gets added when i add an item to FilterData, and the dropdown also populates, but i am not sure how to make a relational database with multiple rows
Here is what I have tried so far
<ItemsControl Grid.Row="1" x:Name="Filter" ItemsSource="{Binding FilterData}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10" Orientation="Horizontal" >
<CheckBox IsChecked="{Binding Group}"/>
<ComboBox x:Name="cmbCondition" ItemsSource="{Binding ConditionList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
DisplayMemberPath="Name" SelectedValuePath="Name" SelectedItem="{Binding ConditionList}" Width="80" Height="23" />
<ComboBox x:Name="cmbType" ItemsSource="{Binding TypeList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
DisplayMemberPath="Name" SelectedValuePath="Name" SelectedItem="{Binding TypeList}" Width="80" Height="23" />
<ComboBox x:Name="cmbOperator" ItemsSource="{Binding OperatorList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
DisplayMemberPath="Name" SelectedValuePath="Name" SelectedItem="{Binding OperatorList}" Width="80" Height="23" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public ObservableCollection<FilterData> _FilterData { get; set; }
public ObservableCollection<ConditionList> _ConditionList { get; set; }
public ObservableCollection<TypeList> _TypeList { get; set; }
public IEnumerable<FilterData> FilterData
{
get { return _FilterData; }
}
public IEnumerable<ConditionList> ConditionList
{
get { return _ConditionList; }
}
public IEnumerable<TypeList> TypeList
{
get { return _TypeList; }
}
//Form Load event
Filter.DataContext = this;
AddRow();
private void AddRow()
{
_ConditionList = new ObservableCollection<ConditionList>()
{
new ConditionList() { Name = "AND" },
new ConditionList() { Name = "OR" }
};
_FilterData.Add(new FilterData
{
Group = true,
// Condition = _ConditionList
});
}
// Modal
public class TypeList
{
public string Name { get; set; }
}
public class ConditionList
{
public string Name { get; set; }
}
public class FilterData
{
public bool Group { get; set; }
public ConditionList Condition { get; set; }
}
If you bind the SelectedItem property of the first ComboBox to a source property of type ConditionList, you could populate the source collection for the second ComboBox (TypeList) in the setter of this one.
Make sure that you implement the INotifyPropertyChanged interface and raise the PropertyChanged event for the source collection property that is being set to a new value, e.g.:
private ConditionList _selectedCondition;
public ConditionList SelectedCondition
{
get { return _selectedCondition; }
set
{
_selectedCondition = value;
NotifyPropertyChanged();
//populate the list...
TypeList = new List<TypeList> { ... };
}
}
public IEnumerable<TypeList> TypeList
{
get { return _TypeList; }
private set { _TypeList = value; NotifyPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
XAML:
<ComboBox x:Name="cmbCondition" ItemsSource="{Binding ConditionList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedCondition, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}" Width="80" Height="23" />
<ComboBox x:Name="cmbType" ItemsSource="{Binding TypeList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" ... />
I have a Datagrid in WPF in which first column has checkbox column and last column has buttons.
Initially, I want to make all the buttons disabled and whenever any checkbox is checked then button of that row should get enabled.
checkbox is unchecked then button should be disabled.
Searched a Lot but could not find anything related to this.
I am not using MVVM.. How to do this on the code behind?
Thanks
This is my Xaml Code and I am simply assigning my itemsource on the code behind
<Grid Grid.Row="2" Grid.ColumnSpan="2" Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center" >
<Border BorderThickness="0" Margin="10" CornerRadius="15">
<Border.BitmapEffect>
<DropShadowBitmapEffect />
</Border.BitmapEffect>
<Grid>
<Border x:Name="BDRounded" BorderThickness="0" CornerRadius="15" Background="White"/>
<DataGrid HorizontalAlignment="Left" x:Name="dgrdActors" RowHeight="74" AutoGenerateColumns="False" CanUserAddRows="False"
BorderThickness="1,0,0,0" BorderBrush="#FFD1A251" FontSize="28" Foreground="#DCA566" FontFamily="Helvetica Neue"
CanUserResizeRows="False" AlternatingRowBackground="Linen" AlternationCount="2" Background="#DCA566"
RowHeaderWidth="0" CanUserResizeColumns="False" CanUserSortColumns="False" CanUserReorderColumns="False"
ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible"
HorizontalGridLinesBrush="#FFD1A251" VerticalGridLinesBrush="#FFD1A251" Height="326"
SelectionMode="Extended" SelectionUnit="FullRow" VirtualizingStackPanel.VirtualizationMode="Standard"
Style="{StaticResource DatagridStyle}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="70" CanUserReorder="False" CanUserResize="False" CanUserSort="False" CellStyle="{StaticResource HitVisibilityCellStyle}" HeaderStyle="{StaticResource HeaderStyle}" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Viewbox Margin="-1">
<!--<CheckBox x:Name="chkboxactors" HorizontalAlignment="Center" VerticalAlignment="Center"
IsChecked="{Binding IsActorChecked, UpdateSourceTrigger=PropertyChanged}"></CheckBox>-->
<CheckBox x:Name="chkboxActors" HorizontalAlignment="Center" VerticalAlignment="Center"></CheckBox>
</Viewbox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Actor Name(s)" Width="300" Binding="{Binding ActorName}" CanUserReorder="False" CellStyle="{StaticResource CellStyle}" CanUserResize="False" CanUserSort="False" HeaderStyle="{StaticResource HeaderStyle}" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Role(s)" Width="300" Binding="{Binding Role}" CanUserReorder="False" CellStyle="{StaticResource CellStyle}" CanUserResize="False" CanUserSort="False" HeaderStyle="{StaticResource HeaderStyle}" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Width="250" CanUserReorder="False" CanUserResize="False" HeaderStyle="{StaticResource HeaderStyle}" CellStyle="{StaticResource HitVisibilityCellStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btnSelectRole" Content="Select Role" Style="{StaticResource DatagridButtonStyle}"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=BDRounded}"/>
</DataGrid.OpacityMask>
</DataGrid>
</Grid>
</Border>
</Grid>
Here you go!
There's no need to do the enabling/disabling in the ViewModel, as this can all be done in XAML.
XAML:
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="100">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="false"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked}" Value="true">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
ViewModel:
public class ViewModel
{
public List<Data> Items { get; private set; }
public ViewModel()
{
Items = new List<Data>
{
new Data(),
new Data(),
new Data()
};
}
}
public class Data : INotifyPropertyChanged
{
private bool _isChecked;
public bool IsChecked
{
get {return _isChecked; }
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(property));
}
}
}
Edit:
Since you've requested a code-behind implementation, here you go. This works by traversing the visual tree based on the current row that the checkbox was clicked from.
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DataGrid AutoGenerateColumns="False" x:Name="MyDataGrid">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Click="CheckBox_Clicked"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="100" x:Name="Button" IsEnabled="false" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
XAML.CS:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyDataGrid.ItemsSource = new List<string>
{
"test",
"test1",
"test2",
"test3"
};
}
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var checkBox = sender as CheckBox;
if (checkBox != null)
{
var associatedRow = VisualTreeHelper.GetParent(checkBox);
while ((associatedRow != null) && (associatedRow.GetType() != typeof(DataGridRow)))
{
associatedRow = VisualTreeHelper.GetParent(associatedRow);
}
var dataGridRow = associatedRow as DataGridRow;
if (dataGridRow != null)
{
var associatedButton = FindChild(dataGridRow, "Button");
if (associatedButton != null)
{
associatedButton.IsEnabled = checkBox.IsChecked.HasValue ? checkBox.IsChecked.Value : false;
}
}
}
}
public static Button FindChild(DependencyObject parent, string childName)
{
if (parent == null) return null;
Button foundChild = null;
var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
var childType = child is Button;
if (!childType)
{
foundChild = FindChild(child, childName);
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (Button)child;
break;
}
}
else
{
foundChild = (Button)child;
break;
}
}
return foundChild;
}
}
If the datagrid is bound to a collection of objects you own (ideally in this case a Facade of a model), then add a IsSelected property to the object that makes up the collection. You can databind your checkbox to that property.
To enable/disable the button, have the model/facade in the collection implement ICommand. You can then use the CanExecute method to enable/disable the button based on the value of IsSelected.
public class User : ICommand, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool IsSelected
{
get
{
return this.isSelected;
}
set
{
this.isSelected = value;
CommandManager.InvalidateRequerySuggested();
this.OnPropertyChanged("IsSelected");
}
}
public bool CanExecute(object parameter)
{
return this.IsSelected;
}
public void Execute(object parameter)
{
// ... Do stuff ...
}
private void RaiseCanExecuteChanged()
{
var handler = this.CanExecuteChanged;
if (handler == null)
{
return;
}
handler(this, new PropertyChangedEventArgs(property));
}
private void OnPropertyChanged(string property)
{
var handler = this.PropertyChanged;
if (handler == null)
{
return;
}
handler(this, new PropertyChangedEventArgs(property));
}
}
Now you bind your checkbox to the IsSelected property. Anytime that the checkbox is selected, the CanExecute method will fire on the class.
Ideally you would use a DelegateCommand class from either MVVMLight or Prism, which have a RaiseCanExecuteChanged() method. This lets you avoid using the CommandManager to requery it.
This can be your DataGrid definition:
<DataGrid x:Name="TestDataGrid" ItemsSource="{Binding source}" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="TestBox" Content="Test" IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Click" IsEnabled="{Binding IsChecked}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Pretty simple code behind:
public partial class MainWindow : Window
{
public ObservableCollection<Model> source { get; set; }
public MainWindow()
{
InitializeComponent();
source = new ObservableCollection<Model>();
source.Add(new Model());
source.Add(new Model());
this.DataContext = this;
}
}
This could be your model:
public class Model : DependencyObject
{
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(Model), new PropertyMetadata(false));
}
Or implement INPC inteface:
public class Model : INotifyPropertyChanged
{
private bool _IsChecked;
public bool IsChecked
{
get { return _IsChecked; }
set
{
_IsChecked = value;
PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
< DataGridTemplateColumn Header="{ Loc CellSettings_Min}" >
<DataGridTemplateColumn.CellTemplate >
< DataTemplate >
< TextBox Width="100" Text="{ Binding Interval }" >
<TextBox.Style>
< Style TargetType = "TextBox" >
< Setter Property="IsEnabled" Value="false" />
< Style.Triggers >
< DataTrigger Binding = "{ Binding AutoScale }" Value= "True" >
< Setter Property = "IsEnabled" Value = "False" />
< /DataTrigger >
< DataTrigger Binding = "{ Binding AutoScale }" Value="False" >
< Setter Property = "IsEnabled" Value = "True" />
</ DataTrigger >
</ Style.Triggers >
</ Style >
</ TextBox.Style >
</ TextBox >
</ DataTemplate >
</ DataGridTemplateColumn.CellTemplate >
</ DataGridTemplateColumn >
You should use MVVM.DataBinding is convenient .
Xaml
<CheckBox Name="checkbox" IsChecked="{Binding Checked, Mode = TwoWay}" />
<Button IsEnabled="{Binding ButtonEnabled , Mode = TwoWay}" />
C#
In ViewModel
public class ViewMode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _buttonChecked = false;
public bool ButtonChecked
{
get
{
return _buttonChecked;
}
set
{
if(value == true)
{
_buttonChecked = value;
OnPropertyChanged("ButtonChecked");
}
}
}
private bool _checked;
public bool Checked
{
get
{
return _checked;
}
set
{
if(value == true)
{
_checked= value;
ButtonChecked = value;
OnPropertyChanged("Checked");
}
}
}
[NotifyPropertyChangedInvocator]
private virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I have two buttons "Search" and "Clear" on my View for which I have two commands on my view model. I have implemented IDataErrorInfo on my ViewModel and validated the input fields. How can I disable validation for the Clear button?
<TextBox Text="{Binding SearchText, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True, ValidatesOnExceptions=True}"
Validation.ErrorTemplate="{StaticResource ErrorTemplate}"/>
<Button Content="Search" Command="{Binding SearchCommand}" />
<Button Content="Clear" Command="{Binding ClearCommand}" />
I am assumed you want to enable / disable the clear button based on validation in the search textbox. I have used the MvvmLight Relaycommand for commanding from the latest MVVMLight using the namespace using GalaSoft.MvvmLight.CommandWpf; refer the code below.
<Window x:Class="DataTemplateSelector_Learning.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="300">
<Grid>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Search Text"/>
<TextBox Width="100" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,
ValidatesOnDataErrors=True, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />
</StackPanel>
<Button Content="Search" Command="{Binding SearchCommand}" />
<Button Content="Clear" Command="{Binding ClearCommand}" />
</StackPanel>
</Grid>
public partial class Window3 : Window
{
public Window3()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
class ViewModel:INotifyPropertyChanged,IDataErrorInfo
{
private string searchText;
private bool enableClear;
public string SearchText
{
get { return searchText; }
set { searchText = value; Notify("SearchText"); }
}
public ICommand SearchCommand { get; set; }
public ICommand ClearCommand { get; set; }
public ViewModel()
{
ClearCommand = new RelayCommand(OnClear, CanClear);
}
private bool CanClear()
{
return enableClear;
}
private void OnClear()
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void Notify(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public string Error
{
get { return String.Empty; }
}
public string this[string columnName]
{
get
{
String errorMessage = String.Empty;
if (!string.IsNullOrEmpty(SearchText))
{
if (SearchText.Length > 0)
{
enableClear = true;
}
else
{
enableClear = false;
}
}
return errorMessage;
}
}
}
I have a class that has a boolean property called IsChecked.
A collection of this class exist in my viewmodel. I've bound a datagrid in my view to this collection. I need to call a method in my viewmodel when the checkbox in the view gets changed. I've implemented INotifyPropertyChanged on the class and it is firing when I check the box but I don't know how to call the method in my viewmodel.
Here's the class in my model...
public class AccountComponent : INotifyPropertyChanged
{
public string Name { get; set; }
public decimal Amount { get; set; }
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
NotifyPropertyChanged("IsChecked");
}
}
public bool Enabled { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Here's the collection in my viewmodel...
private ObservableCollection<AccountComponent> _accountComponents;
private string _accountStatus;
public ObservableCollection<AccountComponent> AccountComponents
{
get { return _accountComponents; }
set
{
_accountComponents = value;
NotifyPropertyChanged("AccountComponents");
CalculateComponentTotal();
}
}
Here's my XAML in the view...
<DataGrid ItemsSource="{Binding AccountComponents}" AutoGenerateColumns="False" Margin="5">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<CheckBox IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" IsEnabled="{Binding Enabled}"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Name}" Header="Component" Width="*" IsReadOnly="True" ElementStyle="{DynamicResource TextBlock-Sketch}"/>
<DataGridTextColumn Binding="{Binding Amount,StringFormat={}{0:C}}" IsReadOnly="True" Header="Charge" ElementStyle="{DynamicResource TextBlock-Sketch}">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Since AccountComponent implements INPC you can observe the IsChecked property in your VM.
say in your VM constructor:
AccountComponents = new ObservableCollection<AccountComponent>();
AccountComponents.CollectionChanged += AccountComponentsOnCollectionChanged;
...
private void AccountComponentsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) {
if (args.NewItems != null && args.NewItems.Count != 0)
foreach (AccountComponent account in args.NewItems)
account.PropertyChanged += AccountOnPropertyChanged;
if (args.OldItems != null && args.OldItems.Count != 0)
foreach (AccountComponent account in args.OldItems)
account.PropertyChanged -= AccountOnPropertyChanged;
}
private void AccountOnPropertyChanged(object sender, PropertyChangedEventArgs args) {
if (args.PropertyName == "IsChecked")
// Invoke Your VM Function Here
}
That should be it.
In Xaml:
add the following namspace..
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Now for you checkbox add the following code:
<CheckBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding CheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
In ViewModel:
public ICommand CheckedCommand
{
get
{
return new DelegateCommand(OnChecked);//Delegate command is the Implemntation of Icommand Interface
}
}
public void OnLogin(object param)
{
//code for you checked event
}
Hope this will help you.
i have a list box. i have an item template with a stack panel in it.
it has a text box and a check box in the item template.
is there a way i can access the check box and enable/disable it on selected index changed?
<UserControl.Resources>
<DataTemplate x:Key="UserApplicationsTemplate">
<StackPanel Orientation="Horizontal"
Margin="2"
ToolTipService.Placement="Mouse"
ToolTipService.ToolTip="{Binding Description, Mode=OneWay}">
<TextBlock Text="{Binding Mode=OneWay}"
TextWrapping="Wrap"
Width="100"
DataContext="{Binding ApplicationName, Mode=OneWay}" />
<CheckBox x:Name="{Binding ApplicationName, Mode=OneWay}"
Margin="5,0,0,0"
Click="IsActive_Clicked"
IsChecked="{Binding IsActive, Mode=OneWay}"
Content="IsActive"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<ListBox x:Name="lstbxUserApplications"
Height="357"
ItemsSource="{Binding Mode=OneWay}"
SelectionMode="Single"
ItemTemplate="{StaticResource UserApplicationsTemplate}" />
Assming you have your ItemsSource binded:
<ListBox x:Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Check, Mode=TwoWay}" />
<TextBlock Text="{Binding Name, Mode=TwoWay}"
Width="100" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="button1"
Content="Uncheck 2"
Click="button1_Click" />
You don't actually need to change the CheckBox.IsChecked property, but the value on your ItemsSource:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
myList.ItemsSource = ListInfo.getInfo();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
ListInfo item = myList.Items[1] as ListInfo;
item.Check = !item.Check;
}
}
public class ListInfo : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
NotifyPropertyChange("Name");
}
}
private bool check;
public bool Check
{
get
{
return check;
}
set
{
check = value;
NotifyPropertyChange("Check");
}
}
public static ObservableCollection<ListInfo> getInfo()
{
ObservableCollection<ListInfo> data = new ObservableCollection<ListInfo>();
data.Add(new ListInfo { Name = "Some text 1", Check = true });
data.Add(new ListInfo { Name = "Some text 2", Check = false });
data.Add(new ListInfo { Name = "Some text 3", Check = true });
return data;
}
public void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
If you take a look at the event handler for the Click event on the button, you can see that all I did was get the item and changed the value. This immediately reflects on the UI.
UPDATE: I see that this was not what you asked for. Here are a couple of ideas:
You can have an event handler for your check box:
<ListBox x:Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Check, Mode=TwoWay}"
IsEnabled="True"
Content="{Binding Name, Mode=TwoWay}"
Click="CheckBox_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And get the reference on the code behind:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox chk = sender as CheckBox;
chk.IsEnabled = false;
}
Of course the problem here is that if you disable the checkbox you lose access to the Click envent.
Another choice is to use the VisualTreeHelper to get reference to your CheckBox when the selection change on the ListBox:
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox list = sender as ListBox;
ListInfo current = list.SelectedItem as ListInfo;
List<CheckBox> checkBoxes = new List<CheckBox>();
getCheckBoxes(list, ref checkBoxes);
foreach (CheckBox checkBox in checkBoxes)
{
if (checkBox.Content.ToString() == current.Name)
{
checkBox.Foreground = new SolidColorBrush(Colors.Red);
}
}
}
public void getCheckBoxes(UIElement parent, ref List<CheckBox> items)
{
int count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (child.GetType() == typeof(CheckBox))
{
items.Add(child as CheckBox);
}
getCheckBoxes(child, ref items);
}
}
}
This of course is not the best option for performance but you get more flexibility.
Here is a solution using RadioButtons:
http://leeontech.wordpress.com/2009/03/18/creating-radiobuttonlist/
It should be easy enough to change it to checkboxes.