RadioButton, Binding, Converters - c#

I am working on Visual Studio 2008, and I have a problem with radiobuttons.
I have 3 radioButton :
<Window.Resources>
// [...]
<DataTemplate x:Key="gridViewReadyTemplate">
<StackPanel>
<RadioButton GroupName="{Binding IdCommand}" IsChecked="{Binding CommandState, Mode=TwoWay, Converter={StaticResource enumBooleanConverter}, ConverterParameter=ready}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="gridViewReportedTemplate">
<StackPanel>
<RadioButton GroupName="{Binding IdCommand}" IsChecked="{Binding CommandState, Mode=TwoWay, Converter={StaticResource enumBooleanConverter}, ConverterParameter=reported}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="gridViewCanceledTemplate">
<StackPanel>
<RadioButton GroupName="{Binding IdCommand}" IsChecked="{Binding CommandState, Mode=TwoWay, Converter={StaticResource enumBooleanConverter}, ConverterParameter=canceled}" />
</StackPanel>
</DataTemplate>
// [...]
<ListView Margin="82,133.32,342.5,0" Name="listView1" ItemsSource="{Binding CurrentTrain.PSCommandCollection, Mode=TwoWay}" Height="111.25" VerticalAlignment="Top">
<ListView.View>
<GridView>
// [...]
<GridViewColumn Header="Préparé" Width="50" CellTemplate="{StaticResource gridViewReadyTemplate }" />
<GridViewColumn Header="Reporté" Width="50" CellTemplate="{StaticResource gridViewReportedTemplate }" />
<GridViewColumn Header="Annulé" Width="50" CellTemplate="{StaticResource gridViewCanceledTemplate }" />
</GridView>
</ListView.View>
</ListView>
The converter :
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string param = (string)parameter;
Enumerators.State state = (Enumerators.State)value;
switch (param)
{
case "ready":
if (state == Enumerators.State.READY)
return true;
return false;
case "reported":
if (state == Enumerators.State.REPORTED)
return true;
return false;
case "canceled":
if (state == Enumerators.State.CANCELED)
return true;
return false;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string param = (string)parameter;
if ((bool?)value == true)
{
switch (param)
{
case "ready":
return Enumerators.State.READY;
case "reported":
return Enumerators.State.REPORTED;
case "canceled":
return Enumerators.State.CANCELED;
}
}
return Enumerators.State.NONE;
}
And the property where radiobutton are binding on :
private Enumerators.State commandState;
public Enumerators.State CommandState
{
get { return commandState; }
set
{
if (commandState != value)
{
commandState = value;
NotifyPropertyChanged("CommandState");
}
else
{
commandState = Enumerators.State.NONE;
NotifyPropertyChanged("CommandState");
}
}
}
When I click on a radiobutton, the state is changing well.
The problem is when I want to uncheck a radiobutton by clicking on it, the state changes, but the radiobutton still checked.
I put breakpoint in my converter, function Convert. For example, if I want to uncheck "ready", the program go in 2 times, for "reported" and "canceled", but not for "ready"...
I really don't understand where is the problem.
Can you explain me how to fix it ?

This is the problem with RadioButton. It loses its binding once it gets unchecked. To fix this, you can bind RadioButton.Command of Radiobuttons to a command of your ViewModel and send a unique CommandParameter to identify which button has called the command in commandhandler.
<RadioButton Command="{Binding MyCommand}" CommandParameter="Radio1"/>
<RadioButton Command="{Binding MyCommand}" CommandParameter="Radio2"/>
<RadioButton Command="{Binding MyCommand}" CommandParameter="Radio3"/>
and in the command handler you can set the property depending on the command parameter received instead of doing it in converter.

Related

How to highlight ListBox Items matching a certain condition

I have 2 ListBoxes defined thus:
<ListBox Name="aggregatesListBox" SelectionChanged="aggregatesList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Amount}"/>
<TextBlock Text="{Binding Path=AccountId}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="postingsListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=PostingId}" />
<TextBlock Text="{Binding Path=Amount}" />
<TextBlock Text="{Binding Path=CreatedDate}" />
<TextBlock Text="{Binding Path=AccountId}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want all items in the postings list to be highlighted (in some way, preferably background colour) if they share the same Account Id as the currently selected aggregated item.
What are my options?
On the advice given I have modified as follows
<ListBox Name="postingsListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<local:IdToBrushConverter x:Key="IdToBrushConverter" />
</StackPanel.Resources>
<StackPanel.Background>
<MultiBinding Converter="{StaticResource IdToBrushConverter}">
<Binding ElementName="aggregatesListBox" Path="SelectedItem.AccountId"/>
<Binding Path="AccountId"/>
</MultiBinding>
</StackPanel.Background>
<TextBlock Text="{Binding Path=PostingId}" />
<TextBlock Text="{Binding Path=Amount}" />
<TextBlock Text="{Binding Path=CreatedDate}"/>
<TextBlock Text="{Binding Path=AccountId}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and
public class IdToBrushConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
System.Windows.Media.Color colour;
if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue || ((int)values[0] != (int)values[1]))
colour = System.Windows.Media.Colors.White;
else
colour = System.Windows.Media.Colors.CornflowerBlue;
return new SolidColorBrush(colour);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("");
}
}
An attribute on the Window is required so that the brush converter can be located
xmlns:local="clr-namespace:MyAccountingThing"
I also changed the behind the scenes logic to use a list of Objects as the ItemsSource of each of the 2 Listboxes rather than the DataRowView I had previously.
Sorted - Thanks!
You could use a multibinding with a converter, here's an example.
XAML
<ListBox x:Name="list1"
ItemsSource="{Binding List1}">
</ListBox>
<ListBox x:Name="list2"
ItemsSource="{Binding List2}"
Grid.Column="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding .}">
<TextBlock.Background>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="SelectedItem" ElementName="list1"/>
<Binding Path="."/>
</MultiBinding>
</TextBlock.Background>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On my silly example, I used the MultiBiding to be able to pass more than one parameter to the Converter, which is the selectedItem on the list1 and the currentItem that ListBox2 is applying the Template, next, I used the converter to compare the received values:
Converter:
public class Converter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var selectedValueList1 = values[0];
var currentItemList2 = values[1];
if(selectedValueList1 == null) // Listbox 1 has no selected Item
return Brushes.Black;
if (selectedValueList1 == currentItemList2)
return Brushes.Red;
return Brushes.Transparent;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And of course, you have to elaborate better the test on your converter, in my example I just pass two strings to be compared.
And that is it, it works like expected.

Triggering button visibility based on position in ListView

I have a ListView with multiple items. The ListViewItems is a template that contains details about the item from the ObservableCollection and a Button.
My goal is for the button to only be visible on the very last ListViewItem. To that end I implemented a converter and bound it to the Button's visibility, which checks ListViewItem's index vs the ListView's count and returns Visibility.Visible or Visibility.Collapsed.
This works fine when the page first loads, but when I add additional items to the ListView, it doesn't update the existing ListViewItems, it only runs the Converter for the new Items.
Is there a nice xaml (MVVM friendly) way to trigger it to run the Binding?
My XAML:
<ListView x:Name="lstBox" ItemsSource="{Binding People}" Background="Yellow" >
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Firstname}" />
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=DataContext.AddPersonCommand}" Content="Add Person" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Converter={StaticResource IsLastItemToVisibilityConverter}}" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My Converter:
public class IsLastItemToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ListViewItem item = value as ListViewItem;
ListView ListView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
int index = ListView.ItemContainerGenerator.IndexFromContainer(item);
if (index == ListView.Items.Count - 1)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Another possibility is to pass the item as a command parameter.
<ListView x:Name="lstBox"
Background="Yellow"
ItemsSource="{Binding People}">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding FirstName}" />
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}},
Path=DataContext.AddPersonCommand}"
CommandParameter="{Binding}"
Content="Add Person"
Visibility="{Binding IsEnabled,
RelativeSource={RelativeSource Self},
Converter={StaticResource BooleanToVisibilityConverter}}" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The CanExecute of the command should return true only when the item is last in the collection. Something like this:
private bool CanAddPerson(object arg)
{
return _people.Last().Equals(arg);
}
The ObservableCollection should contain items of a ViewModel Type (like Person or whatever you want to call it). That viewmodel should contain a Visibility value for each of the items button and you change your converter to a BoolToVisibilityConverter.
In this sollution you just have to update the visibility of items when you change the collection. You have an event where you can do this. Check this answer for more details about the collection changed event.
Hope it helps.

Compare ObservableCollection with Toggle Button listBox?

i have listbox taht fill with list of toggle button in after run the project, if i have observablecollection and i want to compare this ObservableCollection with items in list box where if the item in ObservableCollection exist in listbox i want to make this item (toggle button) checked,
i have tryed to do that but i cant access to toggle button in code behind, becouse the list of toggle buttons show after run the project.
here's my listbox code :
<ListBox x:Name="lbname" ItemsSource="{Binding source}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnitem" Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
and my observableCollection :
IQueryable<items> query = _context.items;
ocitems = new ObservableCollection<items>(query);
In short : How can i compare ObservableCollection items with listbox (Buttons) and if item exist in listbox make the Toggle button that represent the item is checked?
hope this clear.
------------------------------------------ More Detail
i have this list box that show choices for selected item, this listBox filled by ObservableCollection "ocSelectedChoice" :
<ListBox x:Name="lbChoices" ItemsSource="{Binding ocSelectedChoice}" DisplayMemberPath="ChoiceName" HorizontalAlignment="Left" Height="165" VerticalAlignment="Top" Width="186" Margin="567,50,0,0" BorderBrush="#FFC1C1C1" Background="#FFE3E3E3" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="#FFc4d0df"/>
<Setter Property="BorderBrush" Value="#FFC1C1C1"/>
<Setter Property="BorderThickness" Value="0.8"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
when i want to change this item choices, i press the edit button,and will show me windows that has listbox filled by ObservableCollection for all available choices, see the photo, the main problem how to make 'choices 1' lock checked (green one) in choices windows:
<ItemsControl x:Name="icItemGroup" ItemsSource="{Binding PagedSource, ElementName=rdpChoices}" Margin="26,79,0,0" FontWeight="Bold" HorizontalAlignment="Left" Width="506" Height="210" VerticalAlignment="Top" >
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemTemplate -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="tbtnChoices" HorizontalAlignment="Left" VerticalAlignment="Top" FontFamily="tahoma" FontSize="12" Height="45" Width="120" FontWeight="Normal" Margin="0,0,0,5" Background="#FFE8E8E8" BorderBrush="#FFC1C1C1" Foreground="#FF6A6A6A"
Content="{Binding ChoiceName}" TabIndex="{Binding ChoicesID}" Click="tbtnChoices_Click">
<ToggleButton.IsChecked>
<MultiBinding Converter="{StaticResource Choices}">
<Binding Path="ocChoice" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</ToggleButton.IsChecked>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Converter :
public class ChoicesConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Choice _choice = values[0] as Choice;
ObservableCollection<Choice> ocChoices = values[1] as ObservableCollection<Choice>;
return ocChoices.Contains(_choice);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
return null;
}
}
i tried to make this, but sorry still there something unclear for me, please help to solved this issue because it's important for my project.
you should use the multivalue converter to do that i.e bind ToggleButton IsChecked like below:
<ListBox x:Name="lbname" ItemsSource="{Binding source}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnitem" Content="{Binding Name}">
<ToggleButton.IsChecked>
<MultiBinding Converter="{StaticResource MyConverter}">
<Binding />
<Binding Path="DataContext.ObservableCollectionToCompare" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</ToggleButton.IsChecked>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
Here I am assuming that the observalblecollectin to which you want to compare is a property in your view's DataContext.
MyConverter is the multivalue converter that you need to create.
And in the Convert method of your converter you can compare if the item is there in the collection and return true of false accordingly.
public class MyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Item listItem = values[0] as Item;
ObservableCollection<Item> collection = values[1] as ObservableCollection<Item>;
return collection.Contains(listItem);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
return null;
}
}
oky, i solved it, here's my code :
This is the converter :
public class IsSelectedChoiceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool _check = false;
if (value == null)
return false;
Item currentItem = (Item)value;
if (currentItem.ChoicesinItem.Count == 0)
_check = false;
foreach (var _choicesinItem in currentItem.ChoicesinItem)
{
if (currentItem.CurrentChoiceId == _choicesinItem.ChoicesId)
_check = true;
}
return _check;
}
and xaml code :
<ToggleButton x:Name="tbtnChoices" HorizontalAlignment="Left" VerticalAlignment="Top" FontFamily="tahoma" FontSize="12" Height="45" Width="120" FontWeight="Normal" Margin="0,0,0,5" Background="#FFE8E8E8" BorderBrush="#FFC1C1C1" Foreground="#FF6A6A6A"
IsChecked="{Binding Path=Item,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IsSelectedChoice}}"
Content="{Binding Item.CurrentChoiceName}" TabIndex="{Binding Item.CurrentChoiceId}" Click="tbtnChoices_Click">
</ToggleButton>
it's work now, Thanks for anyone help me.

Toggle TextWrapping in TextBox inside FlipView

I have a FlipView where each FlipViewItem contains a TextBox bound to an ObservableCollection and I need to toggle TextWrapping for the TextBox's that are inside the FlipView.
I have tried everything I could think of and no help online thus far. Not a single result I could find.
How can I do this?
XAML:
...
// This part is for the AppBar Toggle button
<ToggleButton x:Name="wordWrapToggleButton" Style="{StaticResource WordWrapAppBarButtonStyle}" />
...
// For the FlipView
<FlipView x:Name="flipView" Grid.Row="1" Margin="0, 50, 0, 0" ItemsSource="{Binding Note, Mode=TwoWay}" Loaded="flipView_Loaded" SelectionChanged="flipView_SelectionChanged" FontSize="12.667">
<FlipView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Contents, Mode=TwoWay}" Tag="{Binding Title, Mode=TwoWay}" TextWrapping="{Binding ElementName=wordWrapToggleButton, Path=.CheckState, Mode=TwoWay}" IsSpellCheckEnabled="True" AcceptsReturn="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="{x:Null}" FontSize="{Binding ElementName=flipView, Path=FontSize, Mode=OneWay}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
You have to create a binding converter that converts from bool to TextWrapping
public class BooleanToTextWrappingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (value is bool && (bool)value) ? TextWrapping.Wrap : TextWrapping.NoWrap;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value is TextWrapping && (TextWrapping)value == TextWrapping.Wrap;
}
}
and use that in your binding
<Page.Resources>
<local:BooleanToTextWrappingConverter x:Key="BooleanToTextWrappingConverter"/>
</Page.Resources>
...
<DataTemplate>
<TextBox Text="{Binding Contents, Mode=TwoWay}"
TextWrapping="{Binding Path=IsChecked, ElementName=wordWrapToggleButton,
Converter={StaticResource BooleanToTextWrappingConverter}}"/>
</DataTemplate>
Note that the TextWrapping binding isn't two-way, as that makes no sense.

WPF GridView with Multiple Checkbox Columns and Select All Column Header

I have a ListView containing several GridViewColumns. Several of the columns are checkboxes. Each column header consists of a checkbox as well, with the intention of checking/unchecking all the checkboxes in that column. Each row's checkboxes are bound to properties in my view model. I've seen several postings where the scenario is a single column of checkboxes, but none of those solutions will work for me, as I have 4 columns of checkboxes. I also need to persist the state of the selections from one visit to the next (all, some or none of the checkboxes in a column could be checked).
Here's an abbreviated version of the XAML for my ListView:
<ListView ItemsSource="{Binding AveragingParameters}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Parameter">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding Name}" />
</DockPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<CheckBox x:Name="chkAvg" IsChecked="{Binding CalcAverage}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
<Grid>
<CheckBox x:Name="chkAvgSelectAll" Content="Avg" ToolTip="Select All" />
</Grid>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<CheckBox x:Name="chkMin" IsChecked="{Binding CalMin}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
<Grid>
<CheckBox x:Name="chkMinSelectAll" Content="Min" ToolTip="Select All" />
</Grid>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I've tried using Commands and Command Parameters, PropertyChanged events on the Checked property, and handling the Checked event in my code behind, but nothing gives me enough information to know what to change in the collection I'm bound to.
I suppose I could create a separate event handler for each, but I'd like to be able to handle this in a single event handler if possible, because eventually I will be creating a custom control that is a bit more malluable in terms of the columns displayed.
Thanks in advance
I've solved my issue using a Command along with a Tag containing the name of the model property I want set and a CommandParameter set to a multi-binding that is bound to the Tag and the Checkbox's IsSelected property. The code follows:
My View's Xaml Resources:
<UserControl.Resources>
<converters:NameValueMultiBindingConverter x:Key="SelectAllConverter" />
</UserControl.Resources>
My View's Xaml:
<ListView ItemsSource="{Binding AveragingParameters}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Parameter">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding Name}" />
</DockPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<CheckBox x:Name="chkAvg" IsChecked="{Binding CalcAverage}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
<CheckBox x:Name="chkAvgSelectAll" Content="Avg"
Tag="CalcAvg" Command="SelectAllCheckedCommand"
ToolTip="Select All">
<MultiBinding Converter="{StaticResource SelectAllConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource self}" />
<Binding Path="IsChecked" RelativeSource="{RelativeSource self}" />
</MultiBinding>
</CheckBox>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<CheckBox x:Name="chkMin" IsChecked="{Binding CalMin}" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
<CheckBox x:Name="chkMinSelectAll" Content="Avg"
Tag="CalcMin" Command="SelectAllCheckedCommand"
ToolTip="Select All">
<MultiBinding Converter="{StaticResource SelectAllConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource self}" />
<Binding Path="IsChecked" RelativeSource="{RelativeSource self}" />
</MultiBinding>
</CheckBox>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
My MultiValueConverter:
public class NameValueMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
var parameters = (object[])values;
return new NameValueConverterResult
{
Name = (string)parameters[0],
Value = parameters[1]
};
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The result object I'm using in the converter:
public class NameValueConverterResult
{
//The name of the model property to set
public string Name { get; set; }
//The value we're setting it to
public object Value { get; set; }
}
The DelegateCommand (I'm using PRISM) and handler in my View Model
public ICommand SelectAllCheckedCommand { get; private set; }
private void OnSelectAllCheckedCommand(object arg )
{
if (arg == null || !(arg is NameValueConverterResult)) return;
NameValueConverterResult prop = arg as NameValueConverterResult;
//Reflect on the model to find the property we want to update.
PropertyInfo propInfo = Averagers.FirstOrDefault().GetType().GetProperty(prop.Name);
if (propInfo == null) return;
//Set the property on the Model
foreach (var item in Averagers)
propInfo.SetValue(item, prop.Value, null);
}
I hope I'm not abusing StackOverflow providing the solution I came up with. I wasn't sure of the etiquette here.
Just hand over as much info as needed and do the rest via reflection, e.g.
<ListView ItemsSource="{Binding DpData}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsActive}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
<!-- Pass collection to Tag property, relevant member info is in the Content,
could also create an array in the Tag if the Content should be a nicer
looking string. -->
<CheckBox Content="IsActive" Click="CheckBox_Click" Tag="{Binding DpData}"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
// This method could be used for all columns,
// as long as they contain the necessary info
// which should be provided in the XAML:
// - Item Collection
// - Property Name
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
var cb = sender as CheckBox;
var items = cb.Tag as IEnumerable;
PropertyInfo prop = null;
foreach (var item in items)
{
if (prop == null)
{
var type = item.GetType();
var propname = cb.Content as string;
prop = type.GetProperty(propname);
}
prop.SetValue(item, cb.IsChecked, null);
}
}
If you want to stick with MVVM approach i would suggest to go for binding approach rather than event handling approach as MVVM avoids writing code in code behind file.
One way could be to simply bind two bool properties in view model with IsChecked Property of both checkboxes. Based on the change notification using INotifyPropetyChanged, you can iterate through your itemssource i.e. AveragingParameters and change either CalMin or CalcAverage

Categories