Grid Hide/Show animation - wpf

I've got some User Control, which is grid with transparent background, on top of that there's another grid that is suppose to change its width when triggers are fired (ultimately it'll be a in/out animation). Purpose was to simply use something different than Visibility that was instantly hiding entire control without any animations Here's the property it's based on:
public static readonly DependencyProperty IsOpenedProperty = DependencyProperty.Register ("IsOpened", typeof (Boolean), typeof (SidePanel), new PropertyMetadata (false));
public bool IsOpened {
get {
if (GetValue (IsOpenedProperty) != null)
return (bool)GetValue (IsOpenedProperty);
else
return false;
}
set {
SetValue (IsOpenedProperty, value);
Console.WriteLine(value);
}
}
And the Grid itself:
<Grid>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Setter Property="Width" Value="50"/>
<Setter Property="Background" Value="Gray"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsOpened}" Value="True">
<Setter Property="Width" Value="350"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsOpened}" Value="False">
<Setter Property="Width" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<TextBlock Text="{Binding ElementName=Side, Path=Width}"/>
</Grid>
Console gives me corect output but triggers don't fire at all.
Just checked one more thing and when I set trigger for x:Null value then it's fired all the time, how is it possible as Get shouldn't ever return null value here?

Alright I just gave up on dependency property here, created private variable to hold the value and added data context with INotifyPropertyChanged interface implementation and now it works.

Related

Hiding context menu based on data trigger

I have a couple of grids in a user control. I want to hide the context menu in a grid based on a property in the DataContext. I have this code:
<Style TargetType="{x:Type ContextMenu}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsLockedNorthGrid}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
I know the IsLockedNorthGrid property works since I'm using it somewhere else in xaml. What am I missing?
Thanks
If you are using Style.Triggers to change the Visibility, be sure you are not setting Visibility to Context Menu inline. Since, inline property has higher priority over the style.
Check if the Visibility is set to a specific value (setting it in a specific element and triggering it won´t work). Also try
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsLockedNorthGrid}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
I was able to solve my problem like so:
<XamDataGrid ContextMenuOpeninig="OnContextMenuOpening">
<XamDataGrid.Resources>
<ContextMenu x:Key="GridContextMenu">...</ContextMenu> </XamDataGrid.Resources>
<XamDataGrid>
Code behind:
private void OnContextMenuOpening(object sender, ContextMenuEventArgs e)
{
var logViewModel = (LogViewModelBase)DataContext;
var grid = sender as XamDataGrid;
var menu = grid.Resources["GridContextMenu"] as ContextMenu;
menu.Visibility = !logViewModel.IsLockedNorthGrid ? Visibility.Hidden : Visibility.Visible;
}
Not that pretty but it works.

Can not change template of ContentControl from style's datatrigger - datatrigger not firing

Hello WPF aficionados,
I have a content control inside a user control that sets it data context to the selected item of a listview inside the same usercontrol. The selected item property on the view model is called Selection.
Here is the content control's declaration:
<ContentControl DataContext="{Binding Selection}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{StaticResource JobSnapShotProgDetail}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding bTandM}" Value="1">
<Setter Property="Template" Value="{StaticResource JobSnapShotProgDetail}"/>
</DataTrigger>
<DataTrigger Binding="{Binding bTandM}" Value="0">
<Setter Property="Template" Value="{StaticResource JobSnapShotTM_Detail}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
The Templates are defined as ControlTemplates in another resource file like:
<ControlTemplate x:Key="JobSnapShotProgDetail" >
...
</ControlTemplate >
<ControlTemplate x:Key="JobSnapShotTM_Detail" >
...
</ControlTemplate >
The binding works great meaning that the template's fields all display the correct data from the Selection object.
My Problem:
I want the content control to use one of two different control templates based on the value of the Selection's bTandM property.
What happens now:
When I change the selection of the listview, which changes the Selection object, the template IS NOT being changed based on the value of the Selection's bTandM property (a sql server bit data type). Yes the Selection object implements iNotifyPropertyChanged, and the ControlTemplate's fields that bind to the Selection's properties all display the correct data without any binding errors in the output window.
What I Tried:
It seems like the datatrigger is not getting "HIT" by the code. I tried to break the datatrigger by adding foo instead of a number which should have not been able to convert, but no error is generated. ie:
<DataTrigger Binding="{Binding bTandM}" Value="foo">
This leads me to believe that the trigger is not firing for some reason.
Question:
Can someone help me figure out why this data trigger has no effect.
Thanks in advance
JK
EDIT 1:
I tried to use a technique found HERE, but it also does not work. THe data triggers are not getting fired.
New attempt using DataTemplate with DataTriggers that target a contentcontrol's template property:
<ItemsControl ItemsSource="{Binding SelectionCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl x:Name="DetailControl" Template="{DynamicResource JobSnapShotProgDetail}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding bTandM}" Value="False">
<Setter TargetName="DetailControl" Property="Template" Value="{DynamicResource JobSnapShotProgDetail}" />
</DataTrigger>
<DataTrigger Binding="{Binding bTandM}" Value="1">
<Setter TargetName="DetailControl" Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Again, the template loads fine and the properties are display correctly for the initial template set in the style setter, but the templates do not change based on the object's bTandM boolean property.
Okay, so this turned out to be an issue with NotifyPropertyChanged.
The selection property of my viewmodel does implement INPC but the problem was that the underlying class type (vw_Job_Snapshot which is a mapped entity from a sql server view) of selection did not.
I had to implement iNPC in the underlying class and then in my viewmodel use the Property Setter for the Selection Property to also notify the specific bTandM property change like so:
Public Property Selection As vw_Job_Snapshot
Get
Return Me._Selection
End Get
Set(ByVal value As vw_Job_Snapshot)
Me._Selection = value
''Notify of specific property changed
value.OnPropertyChanged("bTandM")
_Selection = value
RaisePropertyChanged(JobSnapshotSelectedPropertyName)
End Set
End Property
After this the following code in my view worked perfectly:
<ContentControl DataContext="{Binding Selection}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding bTandM}" Value="False">
<Setter Property="Template" Value="{DynamicResource JobSnapShotProgDetail}"/>
</DataTrigger>
<DataTrigger Binding="{Binding bTandM}" Value="True">
<Setter Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Thanks to everyone who helped
Try using a DataTemplateSelector instead.
Your selector would look something like this (I'm assuming your class is called JobSnapShot):
public class JobSnapShotDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null && item is JobSnapShot)
{
JobSnapShot jobSnapShot = item as JobSnapShot;
if (jobSnapShot.bTandM == 1)
return
element.FindResource("JobSnapShotProgDetail") as DataTemplate;
else
return
element.FindResource("JobSnapShotTM_Detail") as DataTemplate;
}
return null;
}
}
XAML:
<Window.Resources>
<local:JobSnapShotDataTemplateSelector x:Key="myDataTemplateSelector"/>
</Window.Resources>
<ContentControl ItemTemplateSelector="{StaticResource myDataTemplateSelector}" .... />

How do I write a datatrigger to change the value of a dependency property based on a change of a second dependency property?

I want to change the state of a dependency property (Mode) in a UserControl triggered off of a change change of a second dependency property (ViewType).
I tried defining a DataTrigger as follows, but for some reason it doesn't work:
<UserControl.Resources>
<Style TargetType="{x:Type UserControls:MyUserControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ViewType}" Value="ViewType2">
<Setter Property="Mode" Value="Logon"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
To verify that my binding was working correctly I wrote the following test XAML in the same user control:
<Style x:Key="butstyle">
<Style.Triggers>
<DataTrigger Binding="{Binding ViewType}" Value="ViewType2">
<Setter Property="Control.Foreground" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
When I assigned this style to a button, I see the foreground color change to white at the right time, which proves my Binding to ViewType is working.
I seems I need to use a style under usercontrol.resources (like in the first block of code above), but the "Mode" property is never set.
Is this the right way to do this? I'd like to try to keep this in XAML if possible, but I'm not comfortable how triggers should work when they are not related directly to visual elements.
In case its relevant, the "ViewType" bound property is defined in a parent UserControl, and the "Mode" property is defined on MyUserControl.
Update:
I used a converter to find out that my trigger is being called, however my setter is not getting engaged for some reason. Here is the code for my DP which I am trying to set. Breakpoints on neitehr the set() nor the OnModeChanged() are called. Is there anything wrong with my Dependency Property?
public enum ModeStates { Logon, NextState }
public ModeStates Mode
{
get { return (ModeStates)GetValue(ModeProperty); }
set { SetValue(ModeProperty, value); }
}
protected static readonly DependencyProperty ModeProperty = DependencyProperty.Register(
"Mode", typeof(ModeStates), typeof(MyUserControl),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnModeChanged))
);
private static void OnModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// .......
}
Update:
I was able to use DependencyPropertyDescriptor.AddValueChanged() to solve my problem in a pretty clean fashion.
If the dependency properties in question are defined on the UserControl you need to set it's style property, not add a default style inside the resources.
to set the style inline in XAML
<UserControl.Style>
<Style TargetType="{x:Type UserControls:MyUserControl}">
<!-- Triggers -- >
</Style>
</UserControl.Style>
In addition to Adam's answer, are you setting the Mode property in the <UserControl> tag anywhere? If you do, it is overwriting the triggered value.
Also, on occasion I have had issues with a triggered value not getting set unless a default value is also defined in the style.
For example, sometimes this will not work
<UserControl.Style>
<Style TargetType="{x:Type UserControls:MyUserControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ViewType}" Value="ViewType2">
<Setter Property="Mode" Value="Logon"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
while this does
<UserControl.Style>
<Style TargetType="{x:Type UserControls:MyUserControl}">
<Setter Property="Mode" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ViewType}" Value="ViewType2">
<Setter Property="Mode" Value="Logon"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>

Using custom dependency properties as DataTrigger in WPF

I have a custom dependency property that I would like to use as a data trigger. Here is the code behind:
public static readonly DependencyProperty BioinsulatorScannedProperty =
DependencyProperty.Register(
"BioinsulatorScanned",
typeof(bool),
typeof(DisposablesDisplay),
new FrameworkPropertyMetadata(false));
public bool BioinsulatorScanned
{
get
{
return (bool)GetValue(BioinsulatorScannedProperty);
}
set
{
SetValue(BioinsulatorScannedProperty, value);
}
}
I have created a style and control template. My goal is to change the color of some text when the dependency prop is set to true...
<Style x:Key="TreatEye" TargetType="Label">
<Setter Property="Foreground" Value="#d1d1d1" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="30" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Canvas>
<TextBlock x:Name="bioinsulatorText"
Canvas.Left="21" Canvas.Top="33"
Text="Bioinsulator" />
<TextBlock Canvas.Left="21" Canvas.Top="70"
Text="KXL Kit" />
</Canvas>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding BioinsulatorScanned}"
Value="True">
<Setter TargetName="bioinsulatorText"
Property="Foreground" Value="Black" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Despite successfully setting the dependency prop to true programmatically, This trigger condition never fires. This is a real pain to debug!
Thanks in advance.
In this case I am switching the visibility of a button using a datatrigger based on a dependency property FirstLevelProperty.
public static readonly DependencyProperty FirstLevelProperty = DependencyProperty.Register("FirstLevel", typeof(string), typeof(MyWindowClass));
public string FirstLevel
{
get
{
return this.GetValue(FirstLevelProperty).ToString();
}
set
{
this.SetValue(FirstLevelProperty, value);
}
}
You can reference the dependency property FirstLevel(Property) contained (in this case) in a window by using the RelativeSource binding. Also you should set the default setting in the style, that will be overridden by the datatrigger.
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=FirstLevel,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}"
Value="SomeValue">
<Setter Property="Visibility"
Value="Hidden" />
</DataTrigger>
</Style.Triggers>
<Setter Property="Visibility" Value="Visible" />
</Style>
</Button.Style>
It looks like your dependency property is defined inside a DisposableDisplay object that you created. In order for the binding specified to work, an instance of that DisposableDisplay object must be set as the DataContext of the control (label in this case) or any of its ancestors.

'View cannot be shared by more than one ListView' Wpf Error

What is wrong with this code ? It throws the Exception: "View cannot be shared by more than one ListView"
<ListView
ItemsSource="{Binding}"
SelectionMode="Extended">
<ListView.Style>
<Style TargetType="ListView">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyControl, Path=IsCompany}" Value="True">
<Setter Property="View" Value="{StaticResource GridViewCompanies}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MyControl, Path=IsCompany}" Value="False">
<Setter Property="View" Value="{StaticResource GridViewPeople}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MyControl, Path=IsCompany}" Value="{x:Null}">
<Setter Property="View" Value="{StaticResource GridViewBoth}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
public bool? IsCompany
{
get { return (bool?)GetValue(IsCompanyProperty); }
set { SetValue(IsCompanyProperty, value); }
}
public static readonly DependencyProperty IsCompanyProperty =
DependencyProperty.Register("IsCompany", typeof(bool?), typeof(MyControl), new UIPropertyMetadata(null));
EDITED:
I've tried to set the View in code behind and it works. What's the problem with XAML then?
if() ..
MyListView.View = Resources["GridViewCompanies"] as GridView;
The error is because the GridView is being applied to more than one ListView. Is your ListView Style being applied to more than one control? I took a look in Reflector, and it looks like this scenario should work for a single control.
What exactly are you trying to accomplish? I imagine you just want to show different columns. Maybe you can create an attached behavior to generate columns for the GridView depending on the value of the property you are binding to.

Resources