How to bind SelectionStart Property of Text Box? - silverlight

I use this:
<TextBox x:Name="Test"/>
<TextBlock Text="{Binding SelectionStart, ElementName=Test}"/>
but it always shows 0.
How can I treat it?
Thank you.

I ran into this problem (SelectionStart and SelectionLength are not dependency properties) and decided to make a TextBox with bindable selection start and end:
public class SelectionBindingTextBox : TextBox
{
public static readonly DependencyProperty BindableSelectionStartProperty =
DependencyProperty.Register(
"BindableSelectionStart",
typeof(int),
typeof(SelectionBindingTextBox),
new PropertyMetadata(OnBindableSelectionStartChanged));
public static readonly DependencyProperty BindableSelectionLengthProperty =
DependencyProperty.Register(
"BindableSelectionLength",
typeof(int),
typeof(SelectionBindingTextBox),
new PropertyMetadata(OnBindableSelectionLengthChanged));
private bool changeFromUI;
public SelectionBindingTextBox() : base()
{
this.SelectionChanged += this.OnSelectionChanged;
}
public int BindableSelectionStart
{
get
{
return (int)this.GetValue(BindableSelectionStartProperty);
}
set
{
this.SetValue(BindableSelectionStartProperty, value);
}
}
public int BindableSelectionLength
{
get
{
return (int)this.GetValue(BindableSelectionLengthProperty);
}
set
{
this.SetValue(BindableSelectionLengthProperty, value);
}
}
private static void OnBindableSelectionStartChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var textBox = dependencyObject as SelectionBindingTextBox;
if (!textBox.changeFromUI)
{
int newValue = (int)args.NewValue;
textBox.SelectionStart = newValue;
}
else
{
textBox.changeFromUI = false;
}
}
private static void OnBindableSelectionLengthChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var textBox = dependencyObject as SelectionBindingTextBox;
if (!textBox.changeFromUI)
{
int newValue = (int)args.NewValue;
textBox.SelectionLength = newValue;
}
else
{
textBox.changeFromUI = false;
}
}
private void OnSelectionChanged(object sender, RoutedEventArgs e)
{
if (this.BindableSelectionStart != this.SelectionStart)
{
this.changeFromUI = true;
this.BindableSelectionStart = this.SelectionStart;
}
if (this.BindableSelectionLength != this.SelectionLength)
{
this.changeFromUI = true;
this.BindableSelectionLength = this.SelectionLength;
}
}
}

You cannot bind to SelectionStart because it is not a DependencyProperty.

This could be an alternate solution:
View:
<TextBox Text="{Binding Text}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<mvvml:EventToCommand Command="{Binding TextBoxSelectionChangedCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
ViewModel:
#region TextBoxSelectionChangedCommand
RelayCommand<RoutedEventArgs> _TextBoxSelectionChangedCommand = null;
public ICommand TextBoxSelectionChangedCommand {
get {
if (_TextBoxSelectionChangedCommand == null) {
_TextBoxSelectionChangedCommand = new RelayCommand<RoutedEventArgs>((r) => TextBoxSelectionChanged(r), (r) => true);
}
return _TextBoxSelectionChangedCommand;
}
}
protected virtual void TextBoxSelectionChanged(RoutedEventArgs _args) {
YourCursorPositionVariable = (_args.OriginalSource as System.Windows.Controls.TextBox).SelectionStart;
}
#endregion
I agree you has to cast TextBox component type in ViewModel and it's a kind of coupling, but create a custom component will impose to bind on a specific property as well.

As far as I am aware, this feature has not been included in Silverlight 2.0.
Read this article for a work-around solution.

Related

Bindable dynamic DataGrid Columns

Here is my ViewModel class:
public class ColumnViewModel : ViewModelBase
{
private string bindingPropName;
public string BindingPropName
{
get { return bindingPropName; }
set
{
if (bindingPropName != value)
{
bindingPropName = value;
RaisePropertyChanged("BindingPropName");
}
}
}
private string header;
public string Header
{
get { return header; }
set
{
if (header != value)
{
header = value;
RaisePropertyChanged("Header");
}
}
}
}
DataGrid extension classes:
public static class DataGridColumns
{
static DataGridColumns()
{
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridTextColumn));
}
private static readonly DependencyProperty DataGridColumnSettingsProperty = DependencyProperty.RegisterAttached(
"DataGridColumnSettings",
typeof(DataGridColumnSettings),
typeof(DataGridColumn));
private static void SetDataGridColumnSettings(DataGridColumn column, DataGridColumnSettings settings) { column.SetValue(DataGridColumnSettingsProperty, settings); }
private static DataGridColumnSettings GetDataGridColumnSettings(DataGridColumn column) { return column.GetValue(DataGridColumnSettingsProperty) as DataGridColumnSettings; }
public static readonly DependencyProperty DisplayColumnsProperty = DependencyProperty.RegisterAttached(
"DisplayColumns",
typeof(IList),
typeof(DataGridColumns),
new PropertyMetadata(null, DisplayColumnsPropertyChanged));
public static void SetDisplayColumns(DataGrid dataGrid, IList columns) { dataGrid.SetValue(DisplayColumnsProperty, columns); }
public static IList GetDisplayColumns(DataGrid dataGrid) { return dataGrid.GetValue(DisplayColumnsProperty) as IList; }
private static void DisplayColumnsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as DataGrid;
var columns = e.NewValue as IList;
var template = GetColumnSettingsTemplate(target);
CreateColumns(target, columns, template);
}
public static readonly DependencyProperty ColumnSettingsTemplateProperty = DependencyProperty.RegisterAttached(
"ColumnSetupTemplate",
typeof(DataTemplate),
typeof(DataGridColumns),
new PropertyMetadata(null, ColumnSettingsTemplateChanged));
public static void SetColumnSettingsTemplate(DataGrid dataGrid, DataTemplate columnSetupTemplate) { dataGrid.SetValue(ColumnSettingsTemplateProperty, columnSetupTemplate); }
public static DataTemplate GetColumnSettingsTemplate(DataGrid dataGrid) { return dataGrid.GetValue(ColumnSettingsTemplateProperty) as DataTemplate; }
private static void ColumnSettingsTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as DataGrid;
var columns = GetDisplayColumns(target);
var template = e.NewValue as DataTemplate;
CreateColumns(target, columns, template);
}
private static void CreateColumns(DataGrid dataGrid, IList columnViewModels, DataTemplate columnSettings)
{
if (dataGrid == null)
return;
dataGrid.Columns.Clear();
if (columnViewModels == null)
return;
foreach (var column in columnViewModels)
{
var newColumn = new DataGridTextColumn();
newColumn.SetValue(FrameworkElement.DataContextProperty, column);
if (columnSettings != null)
{
var settings = columnSettings.LoadContent() as DataGridColumnSettings;
if (settings != null)
{
settings.Setup(newColumn, column);
SetDataGridColumnSettings(newColumn, settings);
}
}
dataGrid.Columns.Add(newColumn);
}
}
}
public class DataGridColumnSettings : FrameworkElement
{
public static readonly DependencyProperty ColumnBindingPathProperty = DependencyProperty.Register(
"ColumnBindingPath",
typeof(string),
typeof(DataGridColumnSettings),
new PropertyMetadata(null, ColumnBindingPathChanged));
public string ColumnBindingPath
{
get { return GetValue(ColumnBindingPathProperty) as string; }
set { SetValue(ColumnBindingPathProperty, value); }
}
private static void ColumnBindingPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as DataGridColumnSettings;
if (target == null)
return;
target.column.Binding = new Binding(e.NewValue as string);
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
"Header",
typeof(object),
typeof(DataGridColumnSettings));
public object Header
{
get { return GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
private DataGridTextColumn column;
private object viewModel;
public void Setup(DataGridTextColumn column, object columnViewModel)
{
this.column = column;
viewModel = columnViewModel;
this.DataContext = columnViewModel;
if (Header is FrameworkElement)
{
(Header as FrameworkElement).DataContext = columnViewModel;
column.Header = Header;
}
else
BindingOperations.SetBinding(column, DataGridColumn.HeaderProperty, new Binding("Header") { Source = this });
column.Binding = new Binding(ColumnBindingPath);
}
}
and my XAML code:
<DataGrid t:DataGridColumns.DisplayColumns="{Binding Columns}" ItemsSource="{Binding Rows}" AutoGenerateColumns="False">
<t:DataGridColumns.ColumnSettingsTemplate>
<DataTemplate>
<t:DataGridColumnSettings ColumnBindingPath="{Binding BindingPropName}">
<t:DataGridColumnSettings.Header>
<TextBlock Text="{Binding Header}"/>
</t:DataGridColumnSettings.Header>
</t:DataGridColumnSettings>
</DataTemplate>
</t:DataGridColumns.ColumnSettingsTemplate>
</DataGrid>
Everything what i'm trying to achieve is adding CellTemplate:
<DataGrid t:DataGridColumns.DisplayColumns="{Binding Columns}" ItemsSource="{Binding Rows}" AutoGenerateColumns="False">
<t:DataGridColumns.ColumnSettingsTemplate>
<DataTemplate>
<t:DataGridColumnSettings ColumnBindingPath="{Binding BindingPropName}">
<t:DataGridColumnSettings.Header>
<TextBlock Text="{Binding Header}"/>
</t:DataGridColumnSettings.Header>
<t:DataGridColumnSettings.CellTemplate>
<TextBlock Text="{Binding ColumnBindingPath}"/>
</t:DataGridColumnSettings.CellTemplate>
</t:DataGridColumnSettings>
</DataTemplate>
</t:DataGridColumns.ColumnSettingsTemplate>
</DataGrid>
I think the easiest approach would be to add one more dependency property to take a cell template. Then if this exist, create DataGridTemplateColumn instead of DataGridTextColumn when filling the DataGrid, but i have a little problem with Binding my CellTemplate TextBlock to ColumnBindingPath dependency property. Please help ...
The syntax for binding to an attached property would be:
<TextBlock Text="{Binding Path=(t.DataGridColumns.ColumnBindingPath)}"/>
The Path= needs to be written explicitly when binding to attached properties. This has been fixed in WPF 4.5, so there it may be sufficient to write
<TextBlock Text="{Binding (t.DataGridColumns.ColumnBindingPath)}"/>
Note, that you still need parenthesis around the property. Does this answer your question already?

Wpf binding is not working properly

My ViewModel
public class MyViewModel : ViewModelBase
{
// INotifyPropertyChanged is implemented in ViewModelBase
private String _propX;
public String PropX
{
get { return _propX; }
set
{
if (_propX != value)
{
_propX = value;
RaisePropertyChanged(() => PropX);
}
}
}
private String _propY;
public String ServerIP
{
get { return _propY; }
set
{
if (_propY != value)
{
_propY = value;
RaisePropertyChanged(() => ServerIP);
}
}
}
public A()
{
this._propY = "000.000.000.000";
this._propY = "000.000.000.000";
}
}
// EDIT
// This is the command that resets the properties
private RelayCommand _resetFormCommand;
public ICommand ResetConnectionFormCommand
{
get
{
if (_resetFormCommand == null)
{
_resetFormCommand = new RelayCommand(param => this.ExecuteResetFormCommand(), param => this.CanExecuteResetFormCommand);
}
return _resetFormCommand;
}
}
private bool CanExecuteResetFormCommand
{
get
{
return !String.IsNullOrWhiteSpace(this._propX) ||
!String.IsNullOrWhiteSpace(this._propY);
}
}
private void ExecuteResetFormCommand()
{
this._propX = "";
this._propY = "";
}
My View xaml
<TextBox Name="propX" Text="{Binding PropX }" PreviewTextInput="textBox_PreviewTextInput" />
<TextBox Name="propY" Text="{Binding PropY }" PreviewTextInput="textBox_PreviewTextInput" />
<Border>
<Button Content="Reset" Name="resetBtn" Command="{Binding ResetFormCommand}" />
</Border>
My View code behind
private MyViewModel vm;
public ConnectionUserControl()
{
InitializeComponent();
vm = new MyViewModel();
this.DataContext = vm;
}
private void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
ValidateInput(sender as TextBox, e);
}
The reset command resets the properties in my view model but the textboxes still contain their values, the binding is not working properly :(
Am i missing something here?
You should reset the properties, not the private members:
private void ExecuteResetFormCommand()
{
this.PropX = "";
this.PropY = "";
}
How are you resetting the values? You may be overriding the databinding when you reset the values. It would be helpful if you post the code that gets executed when the button is clicked.
In your xaml-code you have to set the binding like:
<TextBox Name="propX" Text="{Binding PropX, Mode=TwoWay}" .../>
binding has to be two way in order for textbox to update itself from viewmodel
In your Code-behind, you have a property ServerIP, which I think you wanted to be named as PropY, since your TextBox binds to a PropY property.
<TextBox Name="propY" Text="{Binding PropY }" PreviewTextInput="textBox_PreviewTextInput" /
Also, you should be assigning the value to your property in your ExecuteResetFormCommand command, and not your private member since the private member does not trigger INotifyPropertyChanged
private void ExecuteResetFormCommand()
{
this.PropX = "";
this.PropY = ""; // <-- Currently you have PropY declared as ServerIP
}

Property won't update it's value if bound

i need an ItemsControl that displays only the selected Item so i have written a customized ItemsControl as seen here:
public class TabView : ItemsControl
{
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register(
"SelectedItem",
typeof(object),
typeof(TabView),
new PropertyMetadata(new PropertyChangedCallback(SelectedItemPropertyChanged)));
private static void SelectedItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//throw new NotImplementedException();
}
public object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { OnSelectedItemChanged(value); }
}
public TabView()
: base()
{
}
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
if (!IsItem(SelectedItem))
{
if (Items.Count > 0)
SelectedItem = Items[0];
else
SelectedItem = null;
}
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return false;
}
protected override DependencyObject GetContainerForItemOverride()
{
Grid grid = new Grid();
grid.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
grid.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
return grid;
}
protected virtual void OnSelectedItemChanged(object newItem)
{
if (SelectedItem == newItem) return;
if (!IsItem(newItem))
{
Debugger.Log(0, "TRACE", "TABVIEW: Index Out of Bounds"+Environment.NewLine);
return;
}
foreach (var item in Items)
{
var container = ItemContainerGenerator.ContainerFromItem(item);
if (container != null)
{
if (item == newItem)
container.SetValue(Control.VisibilityProperty, Visibility.Visible);
else
container.SetValue(Control.VisibilityProperty, Visibility.Collapsed);
}
}
SetValue(SelectedItemProperty, newItem);
}
private bool IsItem(object item)
{
return Items.Contains(item);
}
}
Now I bind my Dataobject SelectedDataTab (MainViewModel.SelectedDataTab) to TabView.SelectedItem.
<uc:TabView
ItemsSource="{Binding BrowserTabs}"
SelectedItem="{Binding SelectedDataTab}">
<uc:TabView.ItemTemplate>
<DataTemplate>
<local:SlitteTabViewSelector Content="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<local:SlitteTabViewSelector.Browser>
<DataTemplate>
<uc:CustomBrowser Margin="0,0,0,0" />
</DataTemplate>
</local:SlitteTabViewSelector.Browser>
<local:SlitteTabViewSelector.MoreTabs>
<DataTemplate>
<uc:MoreTabsControl Margin="0,0,0,0" />
</DataTemplate>
</local:SlitteTabViewSelector.MoreTabs>
</local:SlitteTabViewSelector>
</DataTemplate>
</uc:TabView.ItemTemplate>
</uc:TabView>
If I now start changing SelectedDataTab in my MainViewModel TabView.SelectedItem won't change its value! Did I miss something? I thought if I bind that Property to my MainViewModel.SelectedDataTab it's value gets updated depending on the bound value.
Update: My MainViewModel implements INotifyPropertyChanged correctly and SelectedDataTab will fire it if changed.
RESOLVED
First of all not the Property getter/setter is fired by Binding instead SelectedItemPropertyChanged gets fired.
But in my code SelectedItemPropertyChanged will not get fired because
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
if (!IsItem(SelectedItem))
{
if (Items.Count > 0)
SelectedItem = Items[0];
else
SelectedItem = null;
}
}
overrides the DataBinding. ;)

In WPF, can you use a Command.CanExecute to set the ToolTip?

This is not real code, I know. But it is what I would like to do.
MyBinding.CanExecute += (s, e) =>
{
e.CanExecute = Something.Allow;
if (!e.CanExecute)
e.ToolTip = Something.Reason;
}
Is there a simple way to do it?
Thank you.
From your question, I assume you are doing this from a ViewModel. If so, the simplest thing to do is to have an observable "CanExecute" property for your command, and another string "Reason" property for your tooltip.
Then, you listen for the PropertyChanged event within the ViewModel. When the CanExecute property changes, you simply update the reason.
Here is some sample code, which simply sets the CanExecute property to false when the command is executed:
public MyViewModel()
: base()
{
this.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "SomeCommandCanExecute")
{
if (mSomeCommandCanExecute)
this.Reason = "Some Command Can Execute";
else
this.Reason = "Some Command Cannot Execute Because....";
}
};
}
private RelayCommand mSomeCommand = null;
private Boolean mSomeCommandCanExecute = true;
public RelayCommand SomeCommand
{
get
{
if (mSomeCommand == null)
{
mSomeCommand = new RelayCommand(
cmd => this.ExecuteSomeCommand(),
cmd => this.SomeCommandCanExecute);
}
return mSomeCommand;
}
}
public Boolean SomeCommandCanExecute
{
get { return mSomeCommandCanExecute; }
set { SetProperty("SomeCommandCanExecute", ref mSomeCommandCanExecute, value); }
}
private void ExecuteSomeCommand()
{
this.SomeCommandCanExecute = false;
}
private string mReason = "Some Command Can Execute";
public string Reason
{
get { return mReason; }
set { SetProperty("Reason", ref mReason, value); }
}
And then in your View:
<StackPanel>
<Button Command="{Binding SomeCommand}"
ToolTip="{Binding Reason}"
Content="Some Command"/>
<TextBlock Text="{Binding Reason}"
ToolTip="{Binding Reason}" />
</StackPanel>
Note that you won't see the ToolTip on the disabled button when CanExecute is set to false, which is why I added the TextBlock to show it. You will see the ToolTip on the TextBlock.
This is the best way I believe to accomplish this.
This is the Command definition:
class CustomCommand : RoutedUICommand, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string m_Reason;
public string Reason
{
get { return m_Reason; }
set
{
if (m_Reason == value)
return;
m_Reason = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Reason"));
}
}
}
public class MyCommands
{
public static CustomCommand DoThis = new CustomCommand();
public static CommandBinding DoThisBinding = new CommandBinding
{ Command = DoThis };
public static void SetupCommands()
{
DoThisBinding.CanExecute += (s, e) =>
{
var _Something = DoSomeTest(e.Parameter);
e.CanExecute = _Something.Allow;
if (!e.CanExecute)
(e.Command as CustomCommand).Reason = _Something.Reason;
}
}
}
And this is the XAML implementation:
xmlns:commands="MyNamespace.WhereAreCommands"
<Button Command="{x:Static commands:MyCommands.DoThis}"
ToolTip="{Binding Path=Reason,
Source={x:Static commands:MyCommands.DoThis}}">
Click</Button>

WPF MVVM User Control binding problem

I have an wpf mvvm application. I try to write checkbox list control.
I can bind the checkbox list elements.
Added to this issue, I want to get sum of the selected checkbox list elements values.
I added DependencyProperty and bind it to view model property.
But, they dont fire each other.
CheckBoxList User Control Xaml
<ListBox x:Name="ItemsControl" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsSelected, Mode=TwoWay}"
Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CheckBoxList Code Behind
public partial class CheckBoxList : UserControl
{
public CheckBoxList()
{
InitializeComponent();
}
public static readonly DependencyProperty SelectedCheckBoxItemsValueProperty =
DependencyProperty.Register("SelectedCheckBoxItemsValue", typeof(int), typeof(CheckBoxList),
new FrameworkPropertyMetadata(
0,
new FrameworkPropertyMetadata(0, OnSelectedItemsChanged));
public int SelectedCheckBoxItemsValue
{
get { return (int)GetValue(SelectedCheckBoxItemsValueProperty); }
set { SetValue(SelectedCheckBoxItemsValueProperty, value); }
}
private static int GetSelectedCheckBoxItemsValue(DependencyObject obj)
{
return (int)obj.GetValue(SelectedCheckBoxItemsValueProperty);
}
private static void OnSelectedItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
CheckBoxList checkboxList = obj as CheckBoxList;
ObservableCollection<ISelectableItem> items = checkboxList.DataContext as ObservableCollection<ISelectableItem>;
foreach (var item in items)
{
item.IsSelected = (GetSelectedCheckBoxItemsValue(obj) & item.Value) != 0;
}
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
CheckBoxList checkboxList = sender as CheckBoxList;
ObservableCollection<ISelectableItem> coll = ItemsControl.DataContext as ObservableCollection<ISelectableItem>;
if (coll == null) return;
int count = 0;
foreach (var item in coll)
{
if (item.IsSelected)
{
count += item.Value;
}
}
SelectedCheckBoxItemsValue = count;
}
}
SelectableItem Class
public interface ISelectableItem : INotifyPropertyChanged
{
bool IsSelected { get; set; }
string Text { get; set; }
int Value { get; set; }
string GroupName { get; set; }
}
public class SelectableItem : ISelectableItem
{ ....
ViewModel Property
public int SelectedCheckBoxEnumItemsValue
{
get
{
return _selectedCheckBoxEnumItemsValue;
}
set
{
_selectedCheckBoxEnumItemsValue = value;
NotifyOfPropertyChange("SelectedCheckBoxEnumItemsValue");
}
}
At Binder Class
string selectedItemPropertyName = "Selected" + viewModelProperty.Name + "Value";
var property = viewModelProperties.FirstOrDefault(p => p.Name.Contains(selectedItemPropertyName));
if (property != null)
{
var selectedItemOrValueBinding = new Binding(property.Name)
{
Mode = property.CanWrite ? BindingMode.TwoWay : BindingMode.OneWay,
ValidatesOnDataErrors = Attribute.GetCustomAttributes(property, typeof(ValidationAttribute), true).Any()
};
BindingOperations.SetBinding(control, CheckBoxList.SelectedCheckBoxItemsValueProperty, selectedItemOrValueBinding);
}
Below code solves your problem..
Please Note the segrgation of view models.
<StackPanel>
<TextBlock Text="{Binding Count}"></TextBlock>
<ListBox x:Name="ItemsControl" ItemsSource="{Binding CheckList}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="item" Content="{Binding Text}" IsChecked="{Binding IsSelected, Mode=TwoWay}" Command="{Binding CheckboxCheckedCommand}" CommandParameter="{Binding IsChecked, ElementName=item}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MasterViewModel();
}
}
public class MasterViewModel : INotifyPropertyChanged
{
private List<CheckBoxItem> checkList;
private int count;
public int Count
{
get
{
return count;
}
set
{
count = value;
OnPropertyChanged("Count");
}
}
public List<CheckBoxItem> CheckList
{
get
{
return checkList;
}
set
{
checkList = value;
OnPropertyChanged("CheckList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public MasterViewModel()
{
checkList = new List<CheckBoxItem>();
for (int i = 0; i < 5; i++)
{
CheckBoxItem item = new CheckBoxItem();
item.Text = i.ToString();
item.IsSelected = false;
item.CheckboxCheckedCommand = new RelayCommand(new Action<object>(ExecuteCheckCommand));
checkList.Add(item);
}
}
private void ExecuteCheckCommand(object parameter)
{
if (parameter.GetType() == typeof(bool))
{
bool value = bool.Parse(parameter.ToString());
int val = count;
if (value)
{
val++;
}
else
{
val--;
}
Count = val;
}
}
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
public class CheckBoxItem : INotifyPropertyChanged
{
private bool isSelected;
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
OnPropertyChanged("Text");
}
}
public bool IsSelected
{
get
{
return isSelected;
}
set
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public ICommand CheckboxCheckedCommand
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
public class RelayCommand : ICommand
{
private Action<object> executeCommand;
public RelayCommand(Action<object> executeCommand)
{
this.executeCommand = executeCommand;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
executeCommand(parameter);
}
}

Resources