WPF Datatrigger for an item template - wpf

I have the following xaml inside a text box element that is part of a combo box item template. The combobox's items source is set to a list of objects that have a boolean property AcceptsInput everything works great but I can't get this trigger to fire do I have to do something else.
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding AcceptsInput}" Value="False" >
<Setter Property="Visibility" Value="Hidden"> </Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>

Are you correctly implementing INotifyPropertyChanged in the viewmodel class with the AcceptsInput property?
It should look something like this:
public class MyClass: INotifyPropertyChanged
{
private bool _acceptsInput;
public bool AcceptsInput
{
get { return _acceptsInput; }
set
{
_acceptsInput = value;
OnPropertyChanged("AcceptsInput");
}
}
...
}

Related

User control parameter in wpf mvvm

I want to create a user control with a bool parameter that defines a dynamic behavior, using MVVM pattern, so I can use the user control in another view that way :
<local:MyUserControl BoolParam={Binding aBoolBinding} />
About the coding of the user control, the xaml should use the value of BoolParam to do something like this :
...
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Trigger>
<DataTrigger Binding="{referenceToBoolParam}" Value="False" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
...
Am I supposed to define a property
public bool BoolParam { get; set; }
in the code-behind of the user control, and to code the logic associated to this parameter in the ViewModel of the user control ?
Actually I am a bit confused about it, what is the good practice ?
BoolParam should be a dependency property for you to be able to bind something to it. You define this in the code-behind of MyUserControl:
public bool BoolParam
{
get { return (bool)this.GetValue(BoolParamProperty); }
set { this.SetValue(BoolParamProperty, value); }
}
public static readonly DependencyProperty BoolParamProperty = DependencyProperty.Register(
"BoolParam", typeof(bool), typeof(MyUserControl), new PropertyMetadata(false));
You could then set the DataContext of the UserControl to an instance of a view model that contains a public bool property called aBoolBinding and bind to this one as usual.
View Model:
private bool _b;
public bool aBoolBinding
{
get
{
return _b;
}
set
{
_b = value;
NotifyPropertyChanged();
}
}
View:
<local:MyUserControl BoolParam="{Binding aBoolBinding}" />
This is how data binding works. A target property in the views is bound to a source property of a view model.
Edit:
This binds to the BoolParam property of the UserControl from a TextBox style defined in the UserControl:
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding BoolParam, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="False" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Image Data triggers not working

I have bindings for images in listviews that work fine with boolean conditions. I have created a custom property PlotSettingsFileExists, and an image on a usercontrol but nothing seems to show at runtime.
public partial class BatchDialogUC : UserControl
{
public bool PlotSettingsFileExists
{
get { return File.Exists(Strada.Settings.PlotTemplateFile); }
}
}
<Image Name="imgPltSettings" Width="16" Height="16">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding PlotSettingsFileExists}" Value="true">
<Setter Property="Source" Value="/StradaRPC;component/Resources/imgDrawing.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding PlotSettingsFileExists}" Value="false">
<Setter Property="Source" Value="/StradaRPC;component/Resources/ExlamationMark.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
Does anyone have any suggestions on this?
Looks you have PlotSettingsFileExists property inside your view, but it should be defined in viewmodel and set viewmodel as datacontext of your usecontrol
just set the DataContext. public BatchDialogUC() { InitializeComponent(); DataContext = this; } – Ram Nivas

How to change the style of a row in a WPF DataGrid control when a property of the item in that row changes

I've got a DataGrid control in my WPF application that contains an object. There is a boolean property of that object which can be changed by user actions. I need the style of the row to change when that property's value changes.
I have written a class that descends from StyleSelector:
public class LiveModeSelector : StyleSelector {
public Style LiveModeStyle { get; set; }
public Style NormalStyle { get; set; }
public override Style SelectStyle( object item, DependencyObject container ) {
DataGridRow gridRow = container as DataGridRow;
LPRCamera camera = item as LPRCamera;
if ( camera != null && camera.IsInLiveMode ) {
return LiveModeStyle;
}
return NormalStyle;
}
}
The View Model class in question implements INotifyPropertyChanged, and it raises the PropertyChanged event when the property in question changes.
// Note: The ModuleMonitor class implements INotifyPropertyChanged and raises the PropertyChanged
// event in the SetAndNotify generic method.
public class LPRCamera : ModuleMonitor, ICloneable {
. . .
public bool IsInLiveMode {
get { return iIsInLiveMode; }
private set { SetAndNotify( "IsInLiveMode", ref iIsInLiveMode, value ); }
}
private bool iIsInLiveMode;
. . .
/// </summary>
public void StartLiveMode() {
IsInLiveMode = true;
. . .
}
public void StopLiveMode() {
IsInLiveMode = false;
. . .
}
}
The value of the property is changed when the user performs the required action, but the style doesn't change.
I have placed a breakpoint in the SelectStyle method and I see the breakpoint gets hit when the control is first loaded, but it does not get hit when the property's value changes.
What am I missing?
I found a way to do this that grew out of #Rachel's answer to my question. However, the code details differ somewhat and I want to show exactly what works.
The first step was to combine the two different Styles into one for the DataGridRow class:
<Style TargetType="DataGridRow" x:Key="CameraStyle">
<Setter Property="Foreground" Value="{DynamicResource TextForeground}" />
<Setter Property="Background" Value="{DynamicResource DataBackground}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsInLiveMode}" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
The second step was to set the DataGrid control's RowStyle property to this new style:
<DataGrid . . .
RowStyle={StaticResource CameraStyle}">
. . .
</DataGrid>
This works. The foreground and background of the row changes when the user puts the LPRCamera associated with that row into Live Mode and changes back to normal when they take it out of Live Mode, which is what I was going for.
Thanks #Rachel!
I don't think a StyleSelector listens for PropertyChange notifications, so it doesn't get re-run when the IsInLiveMode property gets changed.
Put your style in a DataTrigger based on IsInLiveMode instead, and it will get re-evaluated anytime the property change notification gets raised.
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}" x:Key="Style1">
<Setter Property="Background" Value="Red" />
</Style>
<Style TargetType="{x:Type DataGridRow}" x:Key="Style2">
<Setter Property="Background" Value="Blue" />
</Style>
</DataGrid.Resources>
<DataGrid.Style>
<Style TargetType="{x:Type DataGrid}">
<Setter Property="RowStyle" Value="{StaticResource Style1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyDataGrid, Path=DataContext.IsInLiveMode}" Value="True">
<Setter Property="RowStyle" Value="{StaticResource Style2}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>

Seting control value on the same stackPanel WPF

I have a situation:
DataGrid with TemplateColumn. Template contains Stack panel with CheckBox and TextBox. What I want is when I press CheckBox then TextBox which is on the same StakcPanel set value to 1.
So in simple
CheckBox -> IsChecked==true -> Set TextBox value to 1 (TextBox on the same StackPanel as CheckBox)
I try with RelativeSource but not work.
Thanks For help.
Well you can bind the Content of the TextBox TextForTextBox, and bind the Checked state to Checked. in your viewModel you would : do
private string _text;
private bool _checked;
public string TextForTextBox
{
get { return _text; }
private set { _text = value;}
}
public bool Checked
{
get { return _checked; }
set
{
if (_checked != value)
{
_checked = value;
Text = _checked ? 1 : = 0;
PropertyChanged("Checked");
PropertyChanged("TextForTextBox");
}
}
}
This is assuming that you have a ViewModel that implements the INotfiyPropertyChanged.
EDIT
Code to change this in pure XAML :
<Grid>
<StackPanel>
<CheckBox x:Name="check" />
<TextBox>
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=check, Path=IsChecked}" Value="True">
<Setter Property="TextBox.Text" Value="1" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=check, Path=IsChecked}" Value="False">
<Setter Property="TextBox.Text" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</Grid>

How to highlight a gridview row if some object value is greater than another?

would like to know how to highlight a gridview row if some object value is greater than another ? (Consider the gridview to be bind to an observablecollection)
Thanks.
Put a property on the class of the items in your observable collection that will get set to true/false based on the comparison you need. Then you should be able to bind to this property in a DataTrigger for a Style on the DataGrid's ItemContainerStyle.
Try this...
<DataGrid ItemsSource="{Binding YourObservableCollection}" >
<DataGrid.ItemContainerStyle>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding YourShouldHighlightProperty}" Value="True">
<Setter Property="Control.Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
You will need to implement a converter to do a > comparison but this shows a highlight
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsParent}" Value="True">
<Setter Property="Background" Value="Gainsboro" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
Use the following code.It wored for me.
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
try
{
foreach (loadtodatagrid item in gridview.ItemsSource)
{
var row = gridview.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (item.item1== item.item2)
{
row.Background = new SolidColorBrush(Colors.Yellow);
}
else
{
// row.Background = new SolidColorBrush(Colors.Green);
}
}
}
catch(Exception ep)
{
//do nothing....
}
LoadingRow="DataGrid_LoadingRow" to datagrid in WPF

Resources