How to Change Property by Trigger in UWP app - c#

i want to Change Visibility of TextBlock when Text property is null or empty in wpf we can do this easily:
<Style TargetType = "TextBlock">
<Setter Property = "Visibility" Value = "Visibile" />
<Style.Triggers>
<Trigger Property = "Text" Value = "">
<Setter Property = "Visibility" Value = "Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
but triggers is not available in uwp, how can i do this in uwp?

<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Text, ElementName=txt}" ComparisonCondition="Equal" Value="">
<Core:ChangePropertyAction TargetObject="{Binding ElementName=txt}" PropertyName="Visibility" Value="Collapsed" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>

Related

XAML binding from 2 XAML objects -Xamarin

I want to set property IsEnabled of button based on switch and picker using binding. Something like this:
XAML:
<Button Text="Start tracking"
AbsoluteLayout.LayoutBounds="0, 1, 1, 0.1"
AbsoluteLayout.LayoutFlags="All"
x:Name="startTrackingButton"
IsEnabled="{Binding}"
Clicked="StartTracking_Clicked"
VerticalOptions="CenterAndExpand"/>
Code behind:
startTrackingButton.BindingContext = (!autoTrackingSwitch.IsToggled || frequencyPicker.IsSet);
This solution does not work. How can I do it? Thank you.
Try using Style:
<Style TargetType="Button">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference autoTrackingSwitch}, Path=IsToggled}" Value="True"/>
<BindingCondition Binding="{Binding Source={x:Reference frequencyPicker}, Path=IsSet}" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Enabled" Value="True"/>
</MultiTrigger>
</Style.Triggers>
</Style>
You can specify it inside Button.Resources of your button.

Bind visibility of a control to combobox selection

I have a combobox which is bound to an Enum datatype. Right now the combobox binding works fine but when I tried to bind the visibility of a checkbox to the combobox selection, this binding is not working as expected. What I wanted to do was whenever the combobox selection is "Restore", I want a checkbox to be visible. Below is the code that I am using.
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cmbOperation, Path=SelectedValue}" Value="Restore">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
I tried changing the Path between SelectedValue, SelectedItem , SelectedValue.TosString() (hopelessly) but I am not getting the checkbox to change its visibility whenever the combobox has "Restore" as its selection. Should I be making any changes in the Enum that I am binding to the Combobox ? If not, what else am I doing wrong?
I'm willing to bet that you've set Visibility on the CheckBox in the XAML:
<CheckBox
Visibility="Collapsed"
>
However, due to the rules of Dependency Property Value Precedence in WPF, that will override anything that happens in the Style. This is by design and it's not a bad idea when you think through all the implications, but it bites everybody who's new to WPF.
It's an easy fix: Just set the starting value in a Setter in the Style. What the Style does, the Style can undo.
<CheckBox
>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cmbOperation, Path=SelectedValue}" Value="Restore">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>

Binding an empty string if value is non-null in wpf

I would like to make a WPF usercontrol that shows a string when and only when the datacontext == null. I'm using the TargetNullValue attribute in binding to display a custom string when the datacontext is null, and that's working as intended. But when the datacontext is non-null, it just shows the ToString value, which I would like to get rid of.
Of course I could solve this easily by using a valueconverter, but I'd like to find a way to solve this with xaml only. Does anyone know a way to do it?
In case you want TextBlock to be shown only in case binding value is null, you can have trigger in place and set Visibility to Visible when binding value is null and otherwise Collapsed always.
<TextBlock Text="{Binding TargetNullValue=NullValue}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Use a data trigger on {x:Null}. There are many options using styles, data templates etc., depending on taste and needs. For instance:
<DataTemplate x:Key="ShowOnNull">
<TextBlock x:Name="text"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter TargetName="text" Property="Text" Value="your custom string"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
...
<ContentPresenter ContentTemplate="{StaticResource ShowOnNull}"
Content="{Binding ...}"/>

Why is my WPF listview code throwing an excpetion when programatically selecting a row

I am trying to programmatically highlight the first row in a WPF listview control using VS2008 with 3.5 of the .NET framework. Here is the C# code for this:
ListViewItem Val = (ListViewItem)ListView1.Items[0];
Val.IsSelected = true;
The code throws an exception at the first line, which is after ListView1 is populated with data. The message in the exception says:
"Unable to cast object of type 'Message.LV1Data' to type 'System.Windows.Controls.ListViewItem'."
LV1Data is the class I am using to bind columns in this control. So, it looks like it is trying to return an LV1Data object instead of a ListViewItem object. Does anyone have any suggestions as to what I am doing wrong or what I need to do in order to programmatically highlight a listview row?
Here is the XAML code for the ListView control:
<ListView x:Name="ListView1" ItemContainerStyle="{StaticResource alternatingListViewItemStyle}" AlternationCount="2" SelectionChanged="ListView1_SelectionChanged"
SelectionMode="Multiple" HorizontalAlignment="Left" ItemsSource = "{Binding ElementName=LobbyWindow, Path=ListCollection1}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Game}">
<GridViewColumnHeader Content="Game" FontWeight="Bold" />
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Stakes}">
<GridViewColumnHeader Content="Stakes" Width="68" FontWeight="Bold" />
</GridViewColumn>
<GridViewColumn Width="30" DisplayMemberBinding="{Binding Seats}">
<GridViewColumnHeader Content="Seats" FontWeight="Bold" />
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
EDIT
<!-- Define the resource for the alternating background background used in the ListView objects. -->
<StackPanel.Resources>
<Style x:Key="alternatingListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Style.Resources>
<!-- Foreground for Selected ListViewItem -->
<!-- <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/> -->
<!-- Background for Selected ListViewItem -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Green"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Brown"/>
</Style.Resources>
<Style.Triggers>
<!-- setting up triggers for alternate background colors -->
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="#FFD9F2BF"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Background" Value="White"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightBlue"></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="LightBlue" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"></Condition>
<Condition Property="ItemsControl.AlternationIndex" Value="0"></Condition>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="LightBlue"></Setter>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"></Condition>
<Condition Property="ItemsControl.AlternationIndex" Value="1"></Condition>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="LightGreen"></Setter>
</MultiTrigger>
</Style.Triggers>
<!-- setting row height here -->
</Style>
</StackPanel.Resources>
You bound to an items source, which means asking for the items[x] will return a type of the data you bound to (whatever type is stored in ListCollection1).
If you want to alter it's IsSelected, you'll have to create that property on the type in ListCollection1, and bind to it in a style or template.
The IsSelected property you create will have to be implemented as a DependencyProperty, or the Type it's in will have to implement INotifyPropertyChanged, and trigger that event when the property changes.
<ListView ItemsSource="...">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Then you'll cast to that dataobject type, and set it's IsSelected value.
Find in your code the ListCollection1. It's definition will look like List<Element>. Element is the type you need to cast to.
Element needs to either look like
public class Element : INotifyPropertyChanged
{
private _IsSelected;
public Boolean IsSelected
{
get { return _IsSelected; }
set
{
_IsSelected = value;
if (PropertyChanged != null)
PropertyChanged("IsSelected");
}
}
//snip Implement interface INotifyPropertyChanged.
//snip your other code
}
-OR-
public class Element : DependencyObject
{
public static DependencyProperty IsSelectedProperty =
DependencyProperty.Register("IsSelected" ...
//snip your other code
}
Then your code should look like this.
Element Val = (Element)ListView1.Items[0];
Val.IsSelected = true;
Items is bound to your business object, so that is why it is not actually returning a listview item. You can try three things:
Use SetSelectedItems and only pass in an IEnumerable of one object
OR, you can get the object and then ask for the ListViewItem it refers to
(ListViewItem)ListView1.ItemContainerGenerator.ContainerFromItem(ListView1.Items[0])
OR, you can bind to the IsSelected property and manage that in your viewmodel

Creating a trigger in a CellTemplate for a ListView? (confusion with Templates in general)

I'm starting to get a little confused as I delve further into WPF and I feel like this example will help in better understanding things. My requirement is this: I have a ListView that is using a binding to a collection of plain .NET objects, I want to do two things:
1) highlight the cell of a row in the ListView if the value is a certain value - I figure I can use the GridViewColumn.CellTemplate for this and create a DataTemplate with a DataTrigger, however I am becoming confused here - is the DataType for the DataTemplate supposed to be the ListViewItem or is it supposed to be the type of the underlying object itself?
This is a general point of confusion for me in WPF ..not knowing when to type it to the underlying collection object (which I've seen in examples) vs the list-item type itself. Here is my first attempt:
<GridViewColumn Header="Position">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type ListViewItem}">
<TextBlock Text="{Binding Path=PositionCode}"></TextBlock>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding PositionCode}" Value="QB">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding PositionCode}" Value="RB">
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding PositionCode}" Value="WR">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
However, this not surprisingly leads to the error message
Cannot find the Template Property 'Background' on the type 'System.Windows.Controls.ContentPresenter'
2) similar to 1) I want to have a similar rule on another criteria I want to highlight the entire row, instead of just the cell based on a similar DataTrigger property but same time I want the cell highlighting to take precedence over the row highlighting.
How would I do this and what template do I need to override to do this? I'm guessing it's the ListView.ItemTemplate but what would the data type be?
Try this:
<GridViewColumn Header="Position">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type ListViewItem}">
<TextBlock Name="TextBlockName" Text="{Binding Path=PositionCode}"></TextBlock>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding PositionCode}" Value="QB">
<Setter TargetName="TextBlockName" Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding PositionCode}" Value="RB">
<Setter TargetName="TextBlockName" Property="Foreground" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding PositionCode}" Value="WR">
<Setter TargetName="TextBlockName" Property="Foreground" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
I think dvvrd's answer addresses your first question. For the other part (building the row style), you can use the ItemContainerStyleSelector.
<ListView ItemContainerStyleSelector="{StaticResource Selector}" ...
I wrote a simple implementation like this:
public class RowStyleSelector : StyleSelector
{
public override System.Windows.Style SelectStyle(object item, System.Windows.DependencyObject container)
{
var i = (item as Item);
if (i.I == 0) return (Style)App.Current.Resources["Selected"];
else return (Style)App.Current.Resources["Normal"];
}
}
Then the different styles, along with the selector reference, go in App.xaml:
<Application.Resources>
<res:RowStyleSelector x:Key="Selector" />
<Style x:Key="Selected" TargetType="ListViewItem">
<Setter Property="Background" Value="DarkGray" />
</Style>
<Style x:Key="Normal" TargetType="ListViewItem">
<Setter Property="Background" Value="LightBlue" />
</Style>
</Application.Resources>
This approach effectively sets the background color depending on criteria in your model (the Item class in my example), with the column highlighting still in effect.

Categories