I have a ListView and each item has a toggle button. I want the to be able to toggle the button when the item is selected from the list, and untoggle when the item is deselected. It has to follow mvvm, so no code behind.
Here is my setup:
<ListView x:Name="stampList"
ItemsSource="{Binding AllStampImages}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0,2,0,0">
<ToggleButton Width="72"
Height="72"
Command="{Binding StampSelectedCommand}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My problem is, when I hit the toggle button the item is not selected. Likewise, when I hit outside the toggle button (still within the boundaries of the listView item), the item is selected but the button is not toggled.
How do I tie the two together?
You might have to bind the Selector.IsSelected property to you custome property. In this case to property of you toggle button.
Try something like:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Selector.IsSelected" Value="{Binding [Value of your toggle button], Mode=TwoWay}" />
</Style>
</ListView.ItemContainerStyle>
The cleanest way to do that is to have a collection of items provided by ViewModel or Model layer.
Each item should have a IsSelected boolean property :
class LineItem
{
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set { isSelected = value; }
}
private String label;
public String Label
{
get { return label; }
set { label = value; }
}
}
There should be some binding to the model IsSelected property :
2.1 On the ListView.ItemTemplate
<ListView x:Name="list1" SelectionMode="Multiple" ItemContainerStyle="{DynamicResource ListViewItemStyle1}" Margin="0,0,334,0">
<ListView.ItemTemplate>
<DataTemplate>
<ToggleButton Margin="5" Content="{Binding Label}" IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</ListView.ItemTemplate>
2.2 On the ListViewItem Template
Create a Template with right clicking on the listview,
In the menu : "Edit additional templates/Edit generated Item container (Empty).
Fill with following code :"
<Style x:Key="ListViewItemStyle1" TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid x:Name="Bd">
<ContentPresenter />
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="#FF204080"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The trigger is based on Model IsSelected property.
The Grid is named Bd in order to change its background in the trigger.
Link to a full working demo : http://1drv.ms/1iyvPgt
Note
I trie to answer closely to the question .
But in my humble opinion, I would not use a ListView May be you have good reasons I gnore.
I 'd prefer to use an ItemsControl that is a listbox that doesn't allow to make a selection.
I'd put Toggle button, with custom Template to put a blue background if needed.
It would remove all the trigger stuff
, ...
Best coding
Related
I have a listbox that loads it's items with Foreground color set to red. What I'd like to do is: upon selecting an item with the mouse, change the foreground color of SelectedItem to black, but make the change persistent so that after deselecting the item, color remains black. Incidentally I want to implement this as a way of showing 'read items' to the user.
Essentially I want something like an implementation of the common property trigger like the code below, but not have the style revert after deselection. I've played around with event triggers as well without much luck.
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="Foreground" Value="Black" /> //make this persist after deselection
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
Thanks in advance!
You could animate the Foreground property:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(ListBoxItem.Foreground).(SolidColorBrush.Color)"
To="Black" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
The downside of this simple approach is that the information is not stored somewhere. This is pure visualization without any data backing. In order to persist the information, so that restarting the application shows the same previous state, you should introduce a dedicated property to your data model e.g IsMarkedAsRead.
Depending on your requirements, you can override the ListBoxItem.Template and bind ToggleButton.IsChecked to IsMarkedAsRead or use a Button which uses a ICommand to set the IsMarkedAsRead property. There are many solutions e.g. implementing an Attached Behavior.
The following examples overrides the ListBoxItem.Template to turn the ListBoxItem into a Button. Now when the item is clicked the IsMarkedAsRead property of the data model is set to true:
Data model
(See Microsoft Docs: Patterns - WPF Apps With The Model-View-ViewModel Design Pattern for an implementation example of the RelayCommand.)
public class Notification : INotifyPropertyChanged
{
public string Text { get; set; }
public ICommand MarkAsReadCommand => new RelayCommand(() => this.IsMarkedAsRead = true);
public ICommand MarkAsUnreadCommand => new RelayCommand(() => this.IsMarkedAsRead = false);
private bool isMarkedAsRead;
public bool IsMarkedAsRead
{
get => this.isMarkedAsRead;
set
{
this.isMarkedAsRead = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
ListBox
<ListBox ItemsSource="{Binding Notifications}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="{TemplateBinding Background}">
<Button x:Name="ContentPresenter"
ContentTemplate="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ItemTemplate}"
Content="{TemplateBinding Content}"
Command="{Binding MarkAsReadCommand}"
Foreground="Red">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsMarkedAsRead}" Value="True">
<Setter TargetName="ContentPresenter" Property="Foreground" Value="Green" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Notification}">
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thanks a lot #BionicCode for the comprehensive answer. I ended up going with another solution which may or may not be good convention; I am a hobbyist.
Firstly, I don't need databacking / persistence.
Concerning the data model solution and overriding ListBoxItem.Template, I am using a prededfined class 'SyndicationItem' as the data class (my app is Rss Reader). To implement your datamodel solution I guess I could hack an unused SyndicationItem property, or use SyndicationItem inheritance for a custom class (I'm guessing this is the most professional way?)
My complete data model is as follows:
ObservableCollection >>> CollectionViewSource >>> ListBox.
Anyway I ended up using some simple code behind which wasn't so simple at the time:
First the XAML:
<Window.Resources>
<CollectionViewSource x:Key="fooCollectionViewSource" Source="{Binding fooObservableCollection}" >
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="PublishDate" Direction="Descending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<Style x:Key="DeselectedTemplate" TargetType="{x:Type ListBoxItem}">
<Setter Property="Foreground" Value="Gray" />
</Style>
</Window.Resources>
<ListBox x:Name="LB1" ItemsSource="{Binding Source={StaticResource fooCollectionViewSource}}" HorizontalContentAlignment="Stretch" Margin="0,0,0,121" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<TextBlock MouseDown="TextBlock_MouseDown" Grid.Column="0" Text="{Binding Path=Title.Text}" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Column="1" HorizontalAlignment="Right" TextAlignment="Center" FontSize="11" FontWeight="SemiBold"
Text="{Binding Path=PublishDate.LocalDateTime, StringFormat='{}{0:d MMM, HH:mm}'}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now the code behind:
Solution 1: this applies a new style when listboxitem is deselected. Not used anymore so the LB1_SelectionChanged event is not present in the XAML.
private void LB1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count != 0)
{
foreach (var lbItem in e.RemovedItems)
{
//get reference to source listbox item. This was a pain.
int intDeselectedItem = LB1.Items.IndexOf(lbItem);
ListBoxItem lbi = (ListBoxItem)LB1.ItemContainerGenerator.ContainerFromIndex(intDeselectedItem);
/*apply style. Initially, instead of applying a style, I used mylistboxitem.Foreground = Brushes.Gray to set the text color.
Howver I noticed that if I scrolled the ListBox to the bottom, the text color would revert to the XAML default style in my XAML.
I assume this is because of refreshes / redraws (whichever the correct term). Applying a new style resolved.*/
Style style = this.FindResource("DeselectedTemplate") as Style;
lbi.Style = style;
}
}
}
Solution 2: The one I went with. Occurs on SelectedItem = true, same effect as your first suggestion.
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
TextBlock tb = e.Source as TextBlock;
tb.Foreground = Brushes.Gray;
}
I am writing a UWP app with a listview. The listviewitems contain a textblock and a checkbox. When the listviewitem is selected, I would like the checkbox to check/uncheck. I would also like to remove the "selected" animation, where the listviewitem turns blue when it is selected.
I have found different solutions, but they all seem to rely on the use of Triggers, which Visual Studio tells me is not available in UWP.
How can I solve this, without triggers in UWP?
My listview:
<ListView Name="ListViewItems" Grid.Row="2">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,1"></Setter>
<Setter Property="Background" Value="White"></Setter>
<Setter Property="Padding" Value="5"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Padding="5,0">
<CheckBox HorizontalAlignment="Right" VerticalAlignment="Center" Name="CheckBoxItem"></CheckBox>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Name="TextblockItem" Text="{Binding}"></TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When the listviewitem is selected, I would like the checkbox to check/uncheck.
You can directly binding the IsChecked property to the CheckBox to the ListViewItem IsSelected property:
<CheckBox
HorizontalAlignment="Right"
Margin="10"
VerticalAlignment="Center"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}}"
Name="CheckBoxItem">
</CheckBox>
Whenever the IsSelected Property of ListViewItem change, the CheckBox will be checked/unchecked.
I would also like to remove the "selected" animation, where the
listviewitem turns blue when it is selected.
The code below can help you achieve this, BUT, it overrides the Template of the Item, which means that you have to write your own template.
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If your ItemSource of the ListView is bound to a collection on a ViewModel, I would suggest you add a bool to the item class of the collection.
So for example if you are showing Persons, add a bool IsSelected field to the Person class.
You can then use this field to bind it to the IsChecked prop of the checkbox in your view, only thing needed to do is be sure to set the Mode=TwoWay
Last thing left to do is toggle this IsSelected field, you do this by binding the SelectedItem of the ListView to a Person property on your ViewModel and each time this is being called ( setter of the property ), toggle the given IsSelected field.
To override the change in colour when an item is selected of the ListView, you need to get a copy of the ListView template and delete the colour setting in the selected state
I have a WPF application with a DataGrid and ListView that share the same ObservableCollection ItemsSource. When the DataGrid's CanUserAddRows property is True it causes the ListView to display the extra item that the DataGrid uses to add new rows.
How can I get the extra row from the DataGrid to not show in the ListView?
I tried using a trigger on the ListView's DataTemplate and checking if the items Id was empty or 0
`<ListView.ItemTemplate>
<DataTemplate>
<Label Margin="-2,0,0,0" Name="CategoryLabel" >
<TextBlock TextWrapping="Wrap" Text="{Binding categoryName}" Height="46"></TextBlock>
</Label>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding categoryId}" Value="0" > <!-- also tried Value="" -->
<Setter TargetName="CategoryLabel" Property="Visibility" Value="Hidden" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>`
I just posted an answer to a problem of changing the template using a data template selector
Change View with its ViewModel based on a ViewModel Property
Possibly just because I have recently looked at this but I wonder if it might be possible to use the same technique here.
Have one template for where the category has a value,then another blank template for values without a category. The important part is you do the test in code rather than XAML so easier to inspect.
You can solve your problem without any modification of your ViewModel or code behind. You can do well without explicitly defining CollectionView's of any kind. Just add to your view's XAML one more (or only) DataTrigger that triggers on the NewItemPlaceholder item of the default view of ListView ItemsSource's collection. Have this trigger to set the UIElement.Visibility attached property to "Hidden". Place it within ItemContainerStyle style triggers. Like this:
<ListView
ItemsSource="{Binding ...}"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
...
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding}"
Value="{x:Static CollectionView.NewItemPlaceholder}">
<Setter Property="UIElement.Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="..." Value="{Binding ...}" />
...
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Label Margin="..." Name="...">
<TextBlock TextWrapping="Wrap"
Text="{Binding ...}" />
</Label>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
I am currently working in C# WPF 4.5 and am attempting to create an interactive grid. Given the grid cell square size (width = height), number of columns and number of rows, I'd like to dynamically generate the grid on the screen.
For the generated grid, I'd like the grid lines to be visible. I'm thinking this could be emulated by just drawing a border within each cell if nothing else. On top of all this, I need an event to be able to determine what cell the user clicks on (i.e., on click return gird column and row) with the ability to select one or more cell at a time.
Any help or ideas on how I could create something like this or is there a better way to go about it? Thanks in advance!
Edit:
So here's some progress I've made:
Created a custom checkbox:
<Style x:Key="styleCustomCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="Background" Background="Transparent">
<Rectangle x:Name="fillCheckBox"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="fillCheckBox" Property="Fill" Value="Transparent"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="fillCheckBox" Property="Fill" Value="Red"/>
<Setter TargetName="fillCheckBox" Property="Opacity" Value=".3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then just populate a grid with the custom checkboxes of that style:
<CheckBox Grid.Column="1" Grid.Row="1" Style="{StaticResource styleCustomCheckBox}" />
So now I'd like to map each of checkboxes within the grid where I can gather whether the checkbox is checked or not and what grid row and column it is in, how would I go about this?
I would use an ItemsControl with its ItemsPanelTemplate set to a UniformGrid, and it's ItemTemplate set to your CheckBox
It would be easiest if you could bind your ItemsControl.ItemsSource to a collection of data objects in your code behind. For example:
<ItemsControl ItemsSource="{Binding MyCollection}">
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="5" Columns="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemTemplate -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="1">
<CheckBox Style="{StaticResource styleCustomCheckBox}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you needed to specify the Row or Column index of the checked item, you could add that to your data item and use a regular Grid instead of a UniformGrid, and apply an ItemContainerStyle like this:
<!-- ItemContainerStyle -->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding ColumnIndex}" />
<Setter Property="Grid.Row" Value="{Binding RowIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
To determine the item clicked on, that depends on how you structure your data object and what you actually want to do in your click.
If you wanted the data item behind the square, you could just use the DataContext, such as
void MyCheckBox_Clicked(object sender, EventArgs e)
{
var selectedItem = ((CheckBox)sender).DataContext;
}
Or if you had something like a data item with an IsChecked property like this:
<CheckBox IsChecked="{Binding IsChecked}"
Style="{StaticResource styleCustomCheckBox}" />
You could easily attach an event to the PropertyChanged event for the data item's IsChecked property, and run some code there.
As a third alternative you could use a Button for your ItemTemplate and pass the selected item as the CommandParameter
<Border BorderBrush="Red" BorderThickness="1">
<Button CommandParameter="{Binding }" ... />
</Border>
I can't give you an definite answer because I don't know your code base and what you're trying to do, but I hope this gives you enough information to give you a rough start and point you in the right direction for your situation.
When a button gets pressed the background (Rectangle Fill) of the button changes. So the user can see what buttons have been pressed and what not.
Problem:
I use a trigger and a Togglebutton to perform the "IsChecked" to change the background.
But the background change may only happens 1 time.
For example:
Button Background = black --> PRESS --> Button Background = blue
But when i press the button again the Button BackGround changes back to black (since its a ToggleButton).
How can i make sure the background only changes 1 time?
EDIT: The button must remain enabled, because a user gives in a reason when they press the button. Meaning if they pick the wrong reason they are able to change it.
<Style x:Key="ButtonStyleReg" TargetType="{x:Type myClasses:RegButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid x:Name="registrationButton">
<Rectangle Name="rectangleBtn" Fill="#FF89959A" Height="Auto" RadiusY="15" RadiusX="15" Stroke="White" Width="Auto"/>
<TextBlock x:Name="reason" TextWrapping="Wrap"
Text="{Binding Reason, StringFormat=\{0\}}"
HorizontalAlignment="Center" Margin="0,7.5,0,0" Height="Auto"
VerticalAlignment="Top" FontWeight="Bold" >
</TextBlock>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<!--<Trigger Property="IsDefaulted" Value="True"/>-->
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="rectangleBtn" Property="Fill" Value="blue" />
</Trigger>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="10.667"/>
Listbox that implements the style:
<ListBox x:Name="lbRegistration" ItemsSource="{Binding RegBtns, ElementName=Window}" Background="{x:Null}"
BorderBrush="{x:Null}" Grid.Column="1"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Disabled" Height="75">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<myClasses:RegistrationButton x:Name="RegistrationButton" HorizontalAlignment="Center" Height="71" Width="148"
Margin="10,0,5,0"
Style="{DynamicResource ButtonStyleRegistration}"
Click="RegistrationButton_Click"
Title="{Binding Title}"
Oorzaak="{Binding Oorzaak}"
DuurStilstand="{Binding DuurStilstand,
Converter={StaticResource DateTimeConverter}}"
BeginStilstand="{Binding BeginStilstand}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Best Regards,
Pete
Very simple would be if you can access the rectangle from code behind:
rectangleBtn.Fill = Brushes.Blue;
If you can't access it - make yourself two styles.
The one that is the original style, the other one is the Blue Style which shall be applied when the user clicks.
In the code behind, on event Click="RegistrationButton_Click"
Set the Style to the BlueStyle.
RegistrationButton.Style = this.FindResource("ButtonStyleRegistration") as Style;
Since you always want it blue, this code is enough as it is. It will always make it Blue for you.
The first time, and any other time.
That way you achieve your requirement and the style will change only once.
When the window is loaded, it will load into the original style (the first style).
So put in your XAML the style "Black" and in the code behind as shown above.
Then this must be removed:
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="rectangleBtn" Property="Fill" Value="blue" />
</Trigger>
Then this:
<myClasses:RegistrationButton x:Name="RegistrationButton" HorizontalAlignment="Center" Height="71" Width="148"
Margin="10,0,5,0"
Style="{DynamicResource ButtonStyleRegistration}"
Click="RegistrationButton_Click"
Shall be:
<myClasses:RegistrationButton x:Name="RegistrationButton" HorizontalAlignment="Center" Height="71" Width="148"
Margin="10,0,5,0"
Style="{DynamicResource ButtonStyleRegBlack}"
Click="RegistrationButton_Click"
That is all.
If you're using an MVVM approach I would recommend binding the background and the Click command to members in the ViewModel. The first time the button is clicked it sets a flag and changes the background color. The next time the button is clicked, if the flag is set, the command returns without changing the background.
XAML:
<ToggleButton Background="{Binding MyBackground}" Command="{Binding OnClickCmd}"/>
ViewModel
public class ViewModel : INotifyPropertyChanged
{
public Brush MyBackground
{
get { return background_; }
set {
background_ = value;
PropertyChanged(this, new PropertyChangedEventArg("MyBackground");
}
}
public ICommand OnClickCmd
{
get {
return new DelegateCommand(()=>{ // DelegateCommand implements ICommand
if(!isBackgroundSet) {
background = Brushes.Red;
isBackgroundSet_ = true;
}
});
}
}
private Brush background_;
private bool isBackgroundSet_;
private event PropertyChangedEventHandler PropertyChagned;
}