I have created a Button and set its background Image. What I want is when the Button is clicked, I want to replace the background Image with another one
How can I accomplish this?
Here is my code with the Button:
<Button x:Name="PopulationReporting" Click="PopulationReporting_Clicked" Width="172"
Height="60" Margin="57,170,57,184">
<Button.Background >
<ImageBrush ImageSource="images/img-2.png" />
</Button.Background>
</Button>
You can do this programmatically (see example here)
or
You can use DataTriggers, where the DataTrigger is bound to a bool value in your ViewModel and changes the Style of your Button. The Button is bound to a Command, so when executed, the Command will change the state of the image (the isPlaying property).
xaml:
<Button Height="23" HorizontalAlignment="Left" Margin="70,272,0,0" Name="buttonPlay" VerticalAlignment="Top" Width="75" Command="{Binding PlayCommand}" CommandParameter="{Binding ElementName=ButtonImage, Path=Source}" >
<Image Name="ButtonImage">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding isPlaying}" Value="True">
<Setter Property="Source" Value="Play.png" />
</DataTrigger>
<DataTrigger Binding="{Binding isPlaying}" Value="False">
<Setter Property="Source" Value="Stop.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
c#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
private bool _isPlaying = false;
private RelayCommand _playCommand;
public ViewModel()
{
isPlaying = false;
}
public bool isPlaying
{
get { return _isPlaying; }
set
{
_isPlaying = value;
OnPropertyChanged("isPlaying");
}
}
public ICommand PlayCommand
{
get
{
return _playCommand ?? new RelayCommand((x) =>
{
var buttonType = x.ToString();
if (null != buttonType)
{
if (buttonType.Contains("Play"))
{
isPlaying = false;
}
else if (buttonType.Contains("Stop"))
{
isPlaying = true;
}
}
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
Related
I am trying to select/unselect all the listview items when checkbox in listview header is clicked.
View (xaml):
<ListView Margin="10" Name="MyLv" ItemsSource="Binding Path=lstData}" SelectionMode="Extended">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<!-- Checkbox column -->
<GridViewColumn>
<GridViewColumn.Header>
<CheckBox x:Name="CheckAll" Command="{Binding CheckAllCommand}"
CommandParameter="{Binding IsChecked, ElementName=CheckAll}" />
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="ID" Width="120" DisplayMemberBinding="{Binding ID}" />
<GridViewColumn Header="Desc" Width="50" DisplayMemberBinding="{Binding Desc}" />
</GridView>
</ListView.View>
</ListView>
Code-Behind Constructor (xaml.cs):
public MyView()
{
DataContext = new MyViewModel();
InitializeComponent();
}
ViewModel:
public ObservableCollection<DataModel> lstData = null;
public MyViewModel()
{
this.lstData = this.LoadData(); // this connects to a database an extract info to be loaded in listview
}
private RelayCommand checkAllCommand;
public ICommand CheckAllCommand
{
get
{
return checkAllCommand ??
(checkAllCommand = new RelayCommand(param => this.SelectUnselectAll(Convert.ToBoolean(param.ToString()))));
}
}
private void SelectUnselectAll(bool isSelected)
{
for (int i = 0; i < this.lstData.Count; i++)
{
this.lstData[i].IsSelected = isSelected;
}
}
Data Model:
public class DataModel
{
public bool IsSelected { get; set; }
public string ID { get; set; }
public string Desc { get; set; }
}
RelayCommand Class:
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
My problem is the following: When I check/uncheck the checkbox in listview header, IsSelected column in listview for each listviewitem is not updated. I want the following behaviour:
If I check the checkbox in the listview header, all listview items will be checked.
If I uncheck the checkbox in the listview header, all listview items will be unchecked.
Your class DataModel must implement INotifyPropertyChanged, and fire the PropertyChanged event when the IsSelected property changes. Otherwise, the Binding of the ListViewItem's IsSelected property isn't notified.
public class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(IsSelected)));
}
}
public string ID { get; set; }
public string Desc { get; set; }
}
I'm trying to bind the SelectionChanged to a command in the code below.
<EventSetter Event="SelectionChanged" Handler="{Binding MyCommand}" />
But unfortunately I'm gettin an NullReferenceException at InitializeComponent();
What can be the problem? The program works if I remove the above single line.
<StackPanel>
<DataGrid ItemsSource="{Binding Items}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"/>
<DataGridComboBoxColumn Header="Color"
SelectedItemBinding="{Binding Color}">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Colors}"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Colors}"/>
<EventSetter Event="SelectionChanged" Handler="{Binding MyCommand}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
<Button Command="{Binding MyCommand}" Width="100" Height="100" Content="Change"/>
</StackPanel>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new Data();
}
}
public class Data
{
/// <summary>
/// A collection that stores the data required
/// to populate the <seealso cref="DataGrid"/> for sheets in paste window.
/// </summary>
private ObservableCollection<Item> _items;
public ObservableCollection<Item> Items
{
get { return _items; }
}
private ICommand _myCommand;
public ICommand MyCommand
{
get
{
return _myCommand ?? (_myCommand = new CommandHandler(() => Change(), _canExecute));
}
}
private bool _canExecute;
public Data()
{
_canExecute = true;
_items = new ObservableCollection<Item>();
_items.Add(new Item("A"));
_items.Add(new Item("B"));
}
public void Change()
{
_items[0].Name = "D";
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
public class Item : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
public string Color { get; set; }
private IList<string> _colors;
public event PropertyChangedEventHandler PropertyChanged;
public IList<string> Colors
{
get { return _colors; }
}
public Item(string name)
{
_name = name;
_colors = new List<string> { "Green", "Blue" };
Color = _colors[0];
}
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler == null) return;
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
EventSetter expects from you to indicate existing event from codebehind file (xaml.cs). It doesn't work with bindings. So create corresponding event handler inside MainWindow.xaml.cs and indicate it in EventSetter or use Interaction.Triggers from Blend, MvvmLight
<Window
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:command="http://www.galasoft.ch/mvvmlight" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<command:EventToCommand
Command="{Binding MyCommand}"
PassEventArgsToCommand="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Window>
i have an app in MVVM pattern ; it contains one textbox and one button;
i add a validation that if textbox is empty , textbox color change to red;
and at this point i want that the button enable be false till the user
enter character in textbox and then button enable change to true;
my XAML Code is:
<Window.Resources>
<ControlTemplate x:Key="ErrorTemplate">
<DockPanel LastChildFill="True">
<Border BorderBrush="Pink" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Margin="10" Text="{Binding ValidateInputText,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True, ValidatesOnExceptions=True}"
Validation.ErrorTemplate="{StaticResource ErrorTemplate}">
</TextBox>
<Button Margin="10" Grid.Row="2" Command="{Binding ValidateInputCommand}"/>
and my command class is:
public class RelayCommand : ICommand
{
private Action WhatToExcute;
private Func<bool> WhenToExecute;
public RelayCommand(Action what,Func<bool>when )
{
WhatToExcute = what;
WhenToExecute = when;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return WhenToExecute();
}
public void Execute(object parameter)
{
WhatToExcute();
}
}
and my viewmodel is:
public class ViewModel : IDataErrorInfo , INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Product product = new Product();
public ViewModel()
{
ValidateInputCommand = new RelayCommand(action, valid);
}
public void action()
{
}
public bool valid()
{
if (product.Name == null)
return false;
return true;
}
public string ValidateInputText
{
get { return product.Name; }
set {
product.Name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(ValidateInputText));
}
}
}
public RelayCommand ValidateInputCommand { get; set; }
public string this[string columnName]
{
get
{
if ("ValidateInputText" == columnName)
{
if (String.IsNullOrEmpty(ValidateInputText))
{
return "Please enter a Name";
}
}
return "";
}
}
public string Error
{
get
{
throw new NotImplementedException();
}
}
}
now when i run my app , the color of text box is red and when i enter a
character it change to normal that is ok but the
button enable is false and does not change
so i could not click button.
what should i do?
The CanExecuteChanged event on your RelayCommand never gets fired. Therefore the button to which the command has been bound will never re-evaluate its IsEnabled status. Your view model could notify the command on changes in its valid status and the command should in turn raise its CanExecuteChanged event.
I have created a Button and set its background Image. What I want is when the Button is clicked, I want to replace the background Image with another one
How can I accomplish this?
Here is my code with the Button:
<Button x:Name="PopulationReporting" Click="PopulationReporting_Clicked" Width="172"
Height="60" Margin="57,170,57,184">
<Button.Background >
<ImageBrush ImageSource="images/img-2.png" />
</Button.Background>
</Button>
You can do this programmatically (see example here)
or
You can use DataTriggers, where the DataTrigger is bound to a bool value in your ViewModel and changes the Style of your Button. The Button is bound to a Command, so when executed, the Command will change the state of the image (the isPlaying property).
xaml:
<Button Height="23" HorizontalAlignment="Left" Margin="70,272,0,0" Name="buttonPlay" VerticalAlignment="Top" Width="75" Command="{Binding PlayCommand}" CommandParameter="{Binding ElementName=ButtonImage, Path=Source}" >
<Image Name="ButtonImage">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding isPlaying}" Value="True">
<Setter Property="Source" Value="Play.png" />
</DataTrigger>
<DataTrigger Binding="{Binding isPlaying}" Value="False">
<Setter Property="Source" Value="Stop.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
c#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel : INotifyPropertyChanged
{
private bool _isPlaying = false;
private RelayCommand _playCommand;
public ViewModel()
{
isPlaying = false;
}
public bool isPlaying
{
get { return _isPlaying; }
set
{
_isPlaying = value;
OnPropertyChanged("isPlaying");
}
}
public ICommand PlayCommand
{
get
{
return _playCommand ?? new RelayCommand((x) =>
{
var buttonType = x.ToString();
if (null != buttonType)
{
if (buttonType.Contains("Play"))
{
isPlaying = false;
}
else if (buttonType.Contains("Stop"))
{
isPlaying = true;
}
}
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
On my datagrid I've got a DataTrigger determining which colour to set the foreground (Text) to be. This value is being stored as a property of my page.
I've got this all working nicely but now I'm giving the user the functionality to set this colour themselves.
My problem is when this colour is set by the user and I update the property how do I make the datagrid now reflect this change.
Example of what I am doing below (PrivateMessages being show in different colour)
<DataTrigger Binding="{Binding Path=IsPrivate}" Value="True">
<Setter Property="Foreground" Value="{Binding ElementName=GridPage, Path=PrivateMessageColour}" />
</DataTrigger>
Any help or guidance would be most appreciated.
Thanks in advance.
Make sure your type implements the INotifyPropertyChanged interface and you fire the change notification on the setter of your publicly exposed property which the DataTrigger is bound to when you modify the color.
EDIT: Below is an example using a TextBox and a Button to change the color...
C#:
public partial class Window1 : Window
{
MyData _data = new MyData();
public Window1()
{
InitializeComponent();
this.DataContext = _data;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_data.ChangeColor();
}
}
public class MyData : INotifyPropertyChanged
{
Random _rand = new Random();
List<String> _colors = new List<string> { "Red", "Black", "Blue" };
public void ChangeColor()
{
MyColor = _colors[_rand.Next(0, 3)];
}
private bool _isActive = true;
public bool IsActive
{
get
{
return _isActive;
}
set
{
_isActive = value;
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
h(this, new PropertyChangedEventArgs("IsActive"));
}
}
private String _myColor = "Green";
public String MyColor
{
get
{
return _myColor;
}
set
{
_myColor = value;
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
h(this, new PropertyChangedEventArgs("MyColor"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
XAML:
<Grid>
<Button Height="25" Click="Button_Click" Content="Change Color" VerticalAlignment="Bottom" />
<TextBox Width="200" Height="100">
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="true">
<Setter Property="TextBox.Background" Value="{Binding MyColor}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>