WPF: DataTrigger for Topmost property of Prism Window XAML - wpf

I am trying to control the Topmost property of a prism popup window with a DataTrigger, so that when a button within the XAML file is pressed, the Topmost property is set to false. I am pretty new to WPF and am not sure what I need to do to get my binding to work.
Note that the IsModal property is set to false and I'd like to keep it that way, unless the IsModal feature could also be styled with a DataTrigger from the button.
Here's the prism Popup with the style and attempted trigger
<prism:InteractionRequestTrigger SourceObject="{Binding DataBarChartRequest, Mode=OneWay}">
<prism:PopupWindowAction IsModal="False" WindowStartupLocation="CenterScreen">
<prism:PopupWindowAction.WindowStyle>
<Style TargetType="{x:Type Window}">
<Setter Property="Topmost" Value="True"/>
<Setter Property="Height" Value="650"/>
<Setter Property="Width" Value="900"/>
<Setter Property="ResizeMode" Value="CanResize"/>
<Setter Property="ShowInTaskbar" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=StopButton, Path=IsPressed}" Value="True">
<Setter Property="Window.Topmost" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</prism:PopupWindowAction.WindowStyle>
<prism:PopupWindowAction.WindowContent>
<local:DataBarChartNotificationView Width="NaN" Height="NaN" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
and here's the button
<RibbonButton Label="Stop"
x:Name="StopButton"
Command="{Binding StopSessionCommand}"
LargeImageSource ="{StaticResource SessionStopGray}"
FontSize="12"
FontWeight="Regular"
Height="60"
Margin="0,10,0,0"
Foreground="White"/>
It seems as though, despite this InteractionRequestTrigger being in the same xaml file as my button, the prism popup cannot find this local source, or it simply won't work. Would like to know if I can style either the IsModal or Topmost property with the button in the XAML file as a DataTrigger or how to fix my binding to do so.

Related

FocusElement does not change focus when I set it using a DataTrigger

I am making a window that shows the user multiple options, with each a radiobutton and a textbox.
When opening this window, the focus should be on the textbox corresponding to the radiobutton that is checked when opening the window (this is all preset, no need to worry about this).
It is important that it gets fixed either in xaml or in the code-behind.
I have used a DataTrigger to change the FocusedElement to the right textbox, however it gets overwritten after it is set.
The relevant code is in the DataTrigger below. The color gets changed correctly, however the FocusElement does not.
I have tried all the options that I have found on stackoverflow and google. The issue does not lie in the DataTrigger or the setting of the FocusedElement. I think it lies in the fact that it gets overridden at the end. I have used Snoop to see the changes in the Keyboard.FocusedElement and it does not show any change.
<DataTemplate x:Uid="DataTemplate_1" >
<RadioButton x:Uid="RadioButton_1" GroupName="Options" IsChecked="{Binding IsSelected}" Margin="4,0,0,0" Name="RadioBtn">
<StackPanel x:Uid="StackPanel_1" Orientation="Horizontal" >
<Label x:Uid="Label_1" Visibility="{Binding IsUserInput, Converter={cs:OppositeVisibilityConverter}}" Content="{Binding Description, Mode=OneWay}" />
<Label x:Uid="Label_2" Visibility="{Binding IsUserInput, Converter={cs:VisibilityConverter}}" Content="Anders, nl: " />
<TextBox x:Uid="MemAnders" Visibility="{Binding IsUserInput, Converter={cs:VisibilityConverter}}" Text="{Binding AlternativeText}"
Name="MemAnders" MinWidth="400" IsTabStop="False"
>
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=MemAnders}"/>
<Setter Property="Background" Value="LightGoldenrodYellow" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected}" Value="False">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=RadioBtn}"/>
<Setter Property="Background" Value="LightBlue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel >
</RadioButton >
</DataTemplate >
The textbox corresponding to the checked radiobutton should be focused. Instead another (parent?) object is focused.
Anyone know a workaround for this?
The work-around turned out to be setting focus to the textbox in the Window_Loaded function.
I used an algorithm provided by Find a WPF element inside DataTemplate in the code-behind to find the correct textbox element. Then I did TextBox.Focus(); and that fixed it.

WPF action on LostFocus textbox

I'm working on a WPF application and i have a little problem.
I have 1 ToggleButton and 1 TextBox. When i click on the ToggleButton, the TextBox apears and gets focus. This is good. But now i want that when i click on another textbox or just somewhere else, that the textbox loses his focus and disapears. I tried this with Differnet triggers and setters, but can't get it to work.
My code now:
<ToggleButton x:Name="SearchButton" Width="100" Height="100" BorderThickness="0" Margin="580,0,0,0" Template="{DynamicResource ButtonBaseControlTemplate1}" Panel.ZIndex="1">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsChecked, ElementName=SearchButton}" Value="True" />
<Condition Binding="{Binding Visibility, ElementName=SearchBox}" Value="Visible"/>
</MultiDataTrigger.Conditions>
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=SearchBox}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton><TextBox x:Name="SearchBox" Margin="100,33,0,34" Visibility="{Binding IsChecked, ElementName=SearchButton, Converter={StaticResource BoolVisibilityConverter}}" Opacity="0" FontSize="24" FontFamily="Arial" Background="{x:Null}" Foreground="#FF7F7F7F" BorderThickness="0">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="TextBox.IsFocused" Value="False">
<Setter Property="ToggleButton.IsChecked" Value="False" TargetName="SearchButton" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The fact, that the styles in the WPF separated from each other, it's just a bunch of settings setters. We can say, that two different styles for controls, with two different visual trees. So when you're trying to style TextBox to access ToggleButton it does not work, because of its visual tree no ToggleButtons.
In WPF for editing elements in the visual tree, and control in particular, uses a template control or controls placed within view of one Style (but this is usually done with the help of templates, such as DataTemplate, or with ControlTemplate).
I think it will suit you to control the Expander. It already has ToggleButton and content. Example:
XAML
<Expander Header="SearchButton">
<TextBox Text="SearchBox: Opened" Background="Gainsboro" />
</Expander>
Output
To change the view of Expander, you need to change his Style. With it, you can set any form and view of control.
For more information see:
Expander in MSDN
Styling and Templating in MSDN
Customizing the Appearance of an Existing Control by Using a ControlTemplate
Data Templating Overview

WPF Toolkit AutoCompleteBox - How to set different background, foreground on dropdown than on textbox

I'm using the AutoCompleteBox control from the WPF Toolkit.
How do I set different background and foreground on item dropdown than on the textbox?
The XAML below applies a different style to the item textblock in the dropdown, but leaves the background behind the dropdown items with the background colour of the autocomplete textbox. Basically I want the autocomplete textbox to have a dark background and the dropdown to have a white background.
<Style x:Key="SearchBox2" TargetType="wpftoolkit:AutoCompleteBox" >
<Setter Property="Background" Value="#3B4044"></Setter>
<Setter Property="Foreground" Value="#FFFFFF"></Setter>
<Setter Property="BorderBrush" Value="#000000"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="Height" Value="25"></Setter>
</Style>
<wpftoolkit:AutoCompleteBox
x:Name="SearchBox"
Grid.Column="0" Grid.Row="0"
ValueMemberPath="SearchDesc"
FilterMode="Contains"
IsTextCompletionEnabled="True"
Text="Search for an app..."
Style="{StaticResource SearchBox2}" >
<wpftoolkit:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding LongDesc}" Foreground="#16509A" Background="White" />
</StackPanel>
</DataTemplate>
</wpftoolkit:AutoCompleteBox.ItemTemplate>
</wpftoolkit:AutoCompleteBox>
Instead of using ItemTemplate, make use of ItemContainerStyle. Please find the code fix below and let me know whether or not this works for you.
Please try this code:
<wpftoolkit:AutoCompleteBox
x:Name="SearchBox"
Grid.Column="0" Grid.Row="0"
FilterMode="Contains"
IsTextCompletionEnabled="True"
Text="Search for an app...">
<wpftoolkit:AutoCompleteBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#16509A"/>
</Style>
</wpftoolkit:AutoCompleteBox.ItemContainerStyle>
</wpftoolkit:AutoCompleteBox>

Datatrigger on contentpresenter.content not working

I am trying to switch the content of a contentpresenter based on a datatrigger.I want to display a usercontrol in the contentpresenter.content, if i have a value set or else i need to display an error message.But the binding on my datatrigger fails stating that the property is not found.I cant get the datacontext to inherit for the datatrigger checking.I can make it work by using the commented out code.But i am confused why it doesn't work the normal way.
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Content" Value="{Binding UC}"/>
<Style.Triggers>
<!--<DataTrigger Binding="{Binding DataContext.HasValue,RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" Value="false">
<Setter Property="Content" Value="No preview"/>
</DataTrigger>-->
<DataTrigger Binding="{Binding HasValue}" Value="false">
<Setter Property="Content" Value="No value"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
If you want to use triggers to display UserControl, you should use ContentControl not ContentPresenter.
I prefer to use ContentPresenter for CustomControls and When I am using the UserControl for views of Custom Data Types in my system and Allow to give dynamic behavior.
Example: To switch templates for ContentPresenter you need to set ContentTemplateSelector like this
<ContentPresenter Content="{Binding MyContent}"
ContentTemplate="{Binding MyContentTemplate}"
ContentTemplateSelector="{Binding MyContentTemplateSelector}"/>
MyContent, MyContentTemplate & MyContentTemplateSelector are Dependency Properties and can be binded wherever you are using its instance.
READ :
Usage of ContentPresenter
What is the difference between ContentControl and ContentPresenter
The binding mentioned in the question won't work as
ContentPresenter’s DataContext is automatically set to the value of
its Content property, while ContentControl’s DataContext is not.
Bindings are resolved relatively to the value of the DataContext property. If you declare a binding on the ContentPresenter, the moment its content is set, the binding would be re-evaluated.
ContentControl.Content Property can be changed on any trigger based on your requirement. If you want to use it to change on PropertyChanged Event of a property of ViewModel, DataTrigger can be used by binding it with a DataTemplate with UserControl instance in it or using static resource of that UserControl.
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Value="{StaticResource UnSelectedDataTemplate}" Property="ContentTemplate" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
<Setter Value="{StaticResource SelectedDataTemplate}" Property="ContentTemplate" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentContro.Style>
</ContentControl>
READ How to use triggers for content template, more details here
Difference in DataTemplate and StaticResource scope is DataTemplate creates a new instance of the template every time its applied.
Whereas, StaticResource is using the same instance of UserControl again (Static Instance).
You can also use EventTriggers to change content base don Control Events like MouseOver etc.
Alternate approach
Very similar to the above with slight difference. Defining as a data template in resources. Triggering for the content change is essentially identical.
...in <x.Resources /> tag:
<DataTemplate x:Key="DesignerTemplate" DataType="{x:Type vm:SolutionViewModel}">
<vw:SolutionDesignerView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SolutionViewModel}">
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoaded}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource DesignerTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
...then:
<ContentControl Content="{Binding Solution}" />
I usually use trigger Like this...
<UserControl>
<UserControl.Resources>
<DataTemplate x:Key="normalTemplate" >
<!-Fav UserControl->
</DataTemplate >
<DataTemplate x:Key="overWriteTempalte">
<!-Fav UserControl-> </DataTemplate>
</UserControl.Resources>
<ContentPresenter x:Name="ContentField"
Content="{Binding}"
ContentTemplate="{StaticResource ResourceKey=normalTemplate}" />
<UserControl.Triggers>
<DataTrigger Binding="{Binding Path=MyProperty}" Value="True">
<Setter TargetName="ContentField" Property="ContentTemplate" Value="{StaticResource ResourceKey=overWriteTempalte}" />
</DataTrigger>
</UserControl.Triggers>
</UserControl>
If Bindings are a problem Use Snoop to Detect binding errors

changing background color of container when textbox is in focus

I have a simple user control with a TextBox. I want to change the color of user control when the TextBox gets the focus. This is what I have:
<UserControl x:Class="OutLookContactList.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root" MinHeight="30" Loaded="UserControl_Loaded">
<UserControl.Resources>
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter TargetName="root" Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
But I get the errot "TargetName property cannot be set on a style Setter". How can I Set the back ground color of user control when text box gets the focus?
Thanks a bunch
Will it work to wrap the contents of your UserControl inside a Border object? If so, you can simply style the Border like so:
<UserControl x:Class="Sample2.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="75" Width="300">
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=txtSearch}" Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel>
<TextBox x:Name="txtSearch" Text="Search" />
<TextBox Text="Other" />
</StackPanel>
</Border>
</UserControl>
Update: (Answering Sheraz' Questions)
I'm not sure why ElementName doesn't work for accessing children within a UserControl. It might have something to do with the way the visual tree is constructed.
As for Trigger vs DataTrigger: Trigger is for dependency properties and DataTrigger is for databound properties (data or other controls). Since you are trying to style the Border, it makes more sense to place the DataTrigger there and have it watch the TextBox than to have the TextBox change the appearance of the Border.
As I understand it, the TargetName property of Setter is only applicable within a DataTemplate or ControlTemplate. (Info from Dr. WPF in this forum post)
If you were changing the background of the text box you need to remove the TargetName property:
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
and change the TextBox that wants this style to be:
<TextBox Style="{StaticResource searchTextBoxStyle}" .... />
However, as you want to change the value of the parent user control this won't give you want you want.
You could certainly do it in the code behind by adding a GotFocus event handler and putting the code to change the background colour in there.
Here's some XAML that works in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Style>
<Style TargetType="Page">
<Setter Property="Background" Value="#CCCCD0" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txtSearch, Path=IsFocused}"
Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Page.Style>
<TextBox x:Name="txtSearch" Width="100"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Page>
You would change the Page object with your UserControl. I find it much easier to test these sorts of things out in a rapid prototyping tool such as Kaxaml before coding up the UserControl in VS.
Note that you have to set the default colour (in this case #CCCCD0) via a property setter and not via an attribute on the Page itself. This is because the attribute would override the value set by the trigger (because it's a style trigger), so even though the trigger would fire, it would always be trumpted by the local attribute specification, meaning that it wouldn't change. I only point this out because it's a fairly common gotcha.

Resources