Is it possible to reload XAML properties of a UserControl? - c#

I have some frameworkElements inside XAML, and I define some properties like background, and cursor.
In code behind, I change these properties, and when an event triggers, I want to reload these initial properties defined in XAML. Is this possible or I need to redifine manually in code behind?
Thanks.

A control defined in XAML is essentially defining an instance. Once you have the instance, the object is just like every other object you deal with. Having access to the instance defined in XAML within your code behind is akin to creating a new object in the code behind and then adjusting its properties at run time.
When you want the property value to change; you don't revert your property changes, you simply change them to what you desire.

I would suggest looking into DataTriggers for making temporary changes based on some value. This will change the value of a property while a specific condition is true, and revert it to its original value when the condition is false.
For example, here's a style that will change the cursor to a Wait cursor while loading, and change the background to Red if it is invalid.
<Style TargetType="{x:Type local:MyUserControl}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoading}" Value="True">
<Setter Property="Cursor" Value="Wait" />
</DataTrigger>
<DataTrigger Binding="{Binding IsValid}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
Of course, you'll have to define the IsLoading and IsValid properties behind your UserControl, and set them to true/false at the appropriate times in your code-behind.

Related

WPF Custom Control That Displays Content Inline or in a Popup

I am creating a custom WPF content control that has a DisplayMode property which can be:
Inline
Popup
When DisplayMode="Inline", my ControlTemplate can use a standard ContentPresenter like normal.
However, when DisplayMode="Popup", I want the Content to be displayed in a Popup control.
How should I solve this problem?
Does it have to happen purely in code when the DisplayMode property changes? How do I move the content of the Content property between a ContentPresenter and the Popup?
It looks like I was trying to make this more complex than it really is.
The solution to this was to create two separate ControlTemplate(s). One that displays inline and one that displays in a Popup control.
Next, all I had to do was create a couple style triggers that change the ControlTemplate based on the value of the DisplayMode property.
It looks like this:
<Style x:Key="MyControlStyle" TargetType="{x:Type my:MyControl}">
<Setter Property="Template" Value="{StaticResource InlineTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DisplayMode}" Value="Inline">
<Setter Property="Template" Value="{StaticResource InlineTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding DisplayMode}" Value="Overlay">
<Setter Property="Template" Value="{StaticResource OverlayTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>

Common datatrigger in Wpf

Is there any way to make this common?
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentEnum}"
Value="{x:Static Enum.Smth}">
<Setter Property="Header"
Value="Other header" />
</DataTrigger>
</Style.Triggers>
Or
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentEnum}"
Value="{x:Static Enum.Smth}">
<Setter Property="Content"
Value="Other title" />
</DataTrigger>
</Style.Triggers>
Would be great if there is some way to pass parameter like "Title" to trigger and use it on every framework element.
I tried to make attached properties:
behaviors:ChangeContentOnCondition.ContentToChange="NewHello"
behaviors:ChangeContentOnCondition.DefaultContent="Hello"
behaviors:ChangeContentOnCondition.ChangeWhenObjectEqualsTo="{x:Static Enum.Smth}"
behaviors:ChangeContentOnCondition.Value="{Binding CurrentEnum}"
This failed when i didnt know how to listen when all properties are set.
Any help would be great. Thanks.
You'll probably find this easier if you create a single Behavior, with all of the attached properties contained within the Behavior class. This will allow you to change the necessary property.
Also, for the "ContentToChange", I'd set the value using a Binding rather than a string value to avoid you having to try to do a property lookup on the Attached object.

WPF DataTrigger binding if parent is typeof

I have a global scrollbar style for my application but I want the scrollbars to appear slightly different if they appear anywhere inside a specific type of control that has its IsActive property set to true. The code below works but I get a binding error every time the scrollbars aren't hosted in the custom control. Is there a way to check the ancestory before trying to set the trigger?
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=docking:DockingWindow}, Path=IsActive}" Value="False">
<Setter TargetName="Background" Property="Fill" Value="{DynamicResource Gray130}" />
</DataTrigger>

Trigger on ContextMenu.IsOpen in XAML

Here's what I'm trying to do:
<Style x:Key="TreeViewItemStyle">
<Setter Property="TreeViewItem.ContextMenu" Value="{StaticResource ContextMenu}" />
<Style.Triggers>
<Trigger Property="TreeViewItem.ContextMenu.IsOpen" Value="True">
<Setter Property="TreeViewItem.BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect GlowColor="Yellow" GlowSize="2"/>
</Setter.Value>
</Setter>
</Trigger>
</Style>
...
But it is obviously not working because Property="TreeViewItem.ContextMenu.IsOpen" is not recognized. Any suggestions to what I need to change?
You can bind to the IsOpened property of the context menu using a DataTrigger:
<DataTrigger Binding="{Binding ContextMenu.IsOpen, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
Unfortunately, since all of the items in TreeView share the same ContextMenu, that will highlight all of them at once. There doesn't seem to be a property that lets you find out which FrameworkElement opened the ContextMenu.
You could handle the ContextMenuOpening and ContextMenuClosing events on the TreeViewItem, since those will bubble up from the control that handled the click and pass through the right TreeViewItem. If you want to do it in XAML, you could use an EventTrigger to start a one-frame animation that changes your property. The cleanest option may be to write an attached behavior that handles the ContextMenuOpening and ContextMenuClosing events and sets an attached property to true when the context menu is open.

Applying a DataTrigger to a Button Whose Binding Comes From Another Control?

I'm trying to apply a DataTrigger to a Button and it depends on a property from the currently selected item of a TreeView. The idea is that I want to change the text of a Button depending on a property of the selected item.
What I have looks like this:
<Button x:Name="m_AddObject" Margin="192.708,0.909,6,6.363" Click="AddObject_Click" >
<DataTrigger Binding="{Binding ElementName=ObjectTreeView, Path=SelectedItem.Removable}" Value="true">
<Setter TargetName="m_AddObject" Property="Content" Value="Remove" />
</DataTrigger>
</Button>
But I can't get it to compile. The Setter complains about "Content" not being valid because it doesn't have a qualifying type name, but if I change it to "Button.Content" it then complains of "Object reference not set to an instance of an object".
I also tried:
<Setter TargetName="m_AddObject.Content" Value="Remove" />
While that compiles, it didn't work either.
I'm stumped.
Any ideas?
Thanks!
DataTriggers should be defined in a Style for the button. What you're trying to do above is essentially use a DataTriggers as the "label" (the "Content", as WPF puts it) for the button (instead of, say, "OK").
This is ad-hoc, so it might not be totally correct, but it's closer to what you want:
<Button x:Name="m_AddObject"
Margin="192.708,0.909,6,6.363"
Click="AddObject_Click">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ObjectTreeView, Path=SelectedItem.Removable}" Value="True">
<Setter Property="Content" Value="Remove" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

Categories