I have a window with different items and different views for each type.
I would like to access the button in the window (parent) from my code behind from the content control.
OutputConfigView:
<ContentControl Margin="5">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedOutputRendererTyp}" Value="{x:Type outTypes:XmlBarcodeRenderer}">
<Setter Property="ContentTemplate" Value="{StaticResource OutputRendererView}"/>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedOutputRendererTyp}" Value="{x:Type outTypes:CsvBarcodeRenderer}">
<Setter Property="ContentTemplate" Value="{StaticResource CsvOutputRendererView}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
.
.
<Button x:Name="CloseButton"
Grid.Column="1"
Click="WindowClose"
Content="Ok"
Margin="0 0 0 -5"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
</Button>
OutputRendererView.xaml.cs:
public partial class OutputRendererView : UserControl
{
public OutputRendererView()
{
InitializeComponent();
}
private void Border_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var parentWindow = (OutputRendererView)this.Parent;
var button = (Button)parentWindow.FindName("CloseButton");
}
In this case the parentWindow is null.
How can I access the button of the calling window from the code behind of my control ?
To access the button inside the user control, you must first find the usercontrol and then the button inside it.
var button = (Button)((UserControl)parentWindow.FindName("userControlName")).FindName("CloseButton");
Related
This question already has answers here:
How do I make a textbox visible and hidden with a checkbox?
(3 answers)
Closed 4 years ago.
I have 3 CheckBoxes and I want to disable/enable two of them when the other one is checked/unchecked. The first step works (if I check checkBoxcaja, the other two checkBoxes are disabled well, but when I uncheck checkBoxcaja, the other two checkBoxes don't return to their original Enabled state.
What am I doing wrong?
I'm a newbie in WPF.
This is the code:
private void checkBoxcaja_Checked(object sender, RoutedEventArgs e)
{
if (checkBoxcaja.IsChecked == true)
{
checkBoxbanderola.IsEnabled = false;
checkBoxletra.IsEnabled = false;
}
else if (checkBoxcaja.IsChecked == false)
{
checkBoxbanderola.IsEnabled = true;
checkBoxletra.IsEnabled = true;
}
}
Thanks in advance
I'm taking a guess here and say you connected this to the Checked event.
Well, that's only fired if the box is checked. There is an Unchecked event that is fired when it is unchecked so you need to connect to that as well. Half you method belongs there.
private void checkBoxcaja_Checked(object sender, RoutedEventArgs e)
{
checkBoxbanderola.IsEnabled = false;
checkBoxletra.IsEnabled = false;
}
private void checkBoxcaja_Unchecked(object sender, RoutedEventArgs e)
{
checkBoxbanderola.IsEnabled = true;
checkBoxletra.IsEnabled = true;
}
Don't forget to hook them up. Alternatively, you can use the same event handler for both.
You can also do this completely in XAML with Datatriggers:
<CheckBox x:Name="CBOne" Grid.Column="1" Grid.Row="3" Content="One" HorizontalAlignment="Center" VerticalAlignment="Center"></CheckBox>
<CheckBox x:Name="CBTwo" Grid.Column="2" Grid.Row="3" Content="Two" HorizontalAlignment="Left" VerticalAlignment="Center">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="True">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="False">
<Setter Property="IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<CheckBox x:Name="CBThree" Grid.Column="2" Grid.Row="3" Content="Three" HorizontalAlignment="Right" VerticalAlignment="Center">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="True">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="False">
<Setter Property="IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
In WPF I have this code for disabling a menuitem on a certain condition:
private void gridListPlayers_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
Player player = (Player)gridListPlayers.SelectedItem;
if(player.Owner.GUID == Guid.Empty.ToString())
{
propMenuItem.IsEnabled = false;
}
else
{
propMenuItem.IsEnabled = true;
}
}
I'm trying to achieve the same result of that function via XAML. Is there a simple way to do that?
You can set the visibility on or off according to a property in your selected Item. So create read only property ToggleMenuVisible, which returns (Owner.GUID != Guid.Empty.ToString()) and then in your xaml do something like:
<MenuItem x:Name="MyToggleMenu" Header="My Toggle Menu" >
<MenuItem.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.ToggleMenuVisible}" Value="False">
<Setter Property="UIElement.Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem.ToggleMenuVisible}" Value="True">
<Setter Property="UIElement.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
Obviously you will need to include SelectedItem in your view's model.
I have this Border style:
<Border.Style>
<Style x:Uid="Style_36" TargetType="Border">
<Setter x:Uid="Setter_94" Property="BorderBrush" Value="Transparent"/>
<Style.Triggers>
<DataTrigger x:Uid="DataTrigger_36" Binding="{Binding SelectedItem, ElementName=comboActiveStudentAssignmentType}"
Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}">
<Setter x:Uid="Setter_95" Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
I know how to place a style into the Window.Resources and then apply it to any control. But I need to tweak each instance. In the text:
<Border.Style>
<Style x:Uid="Style_36" TargetType="Border">
<Setter x:Uid="Setter_94" Property="BorderBrush" Value="Transparent"/>
<Style.Triggers>
<DataTrigger x:Uid="DataTrigger_36" Binding="{Binding SelectedItem, ElementName=comboActiveStudentAssignmentType}"
Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}">
<Setter x:Uid="Setter_95" Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
This bit:
Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}">
needs to change for each Border on the window. So, how can I set up a style to simplify my code but allow this property to change?
Possible?
Update
Since each border should only diaplay when the combo is a certain value, and the suggestion was to put all the data triggers into the style template, I began by trying:
<Style x:Uid="Style_38" x:Key="StudentAssignmentFocusedBorder" TargetType="Border">
<Setter x:Uid="Setter_94" Property="BorderBrush" Value="Transparent"/>
<Style.Triggers>
<MultiDataTrigger x:Uid="MultiDataTrigger_5">
<MultiDataTrigger.Conditions>
<Condition x:Uid="Condition_11" Binding="{Binding SelectedtItem, ElementName=comboActiveStudentAssignmentType}" Value="{x:Static StudentInfoEnums:StudentAssignmentType.Student1Main}"/>
<Condition x:Uid="Condition_12" Binding="{Binding Name, Mode=OneWay, RelativeSource={RelativeSource Self}}" Value="borderMainHallStudent1"/>
</MultiDataTrigger.Conditions>
<Setter x:Uid="Setter_95" Property="BorderBrush" Value="Red"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
But that doesn't work.
This NOT beautiful but enhancing your possibilities, since you can bind your StudentInfoEnums:StudentAssignmentType.Student1Main-Enum.
Some random demo-XAML to Test:
<Window x:Class="SelectButtonSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SelectButtonSample"
mc:Ignorable="d"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="MainWindow" >
<Grid Height="200">
<StackPanel>
<Button Content="Click me" Width="80" Height="20" >
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="Two"/>
</i:Interaction.Behaviors>
</Button>
<CheckBox Content="Click me" x:Name="chk">
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="Three"/>
</i:Interaction.Behaviors>
</CheckBox>
<ListView>
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="One"></local:MyBorderBehavior>
</i:Interaction.Behaviors>
<ListViewItem Content="Item1">
<i:Interaction.Behaviors>
<local:MyBorderBehavior MyEnumPropery="Four"></local:MyBorderBehavior>
</i:Interaction.Behaviors>
</ListViewItem>
<ListViewItem>Item 2</ListViewItem>
<ListViewItem>Item 3</ListViewItem>
<ListViewItem>Item 4</ListViewItem>
</ListView>
</StackPanel>
</Grid>
</Window>
My Demo-Enum:
public enum MyEnum
{
One,
Two,
Three,
Four
}
The Magic:
public class MyBorderBehavior : Behavior<Control>
{
public MyEnum MyEnumPropery {
get { return (MyEnum) GetValue(MyEnumProperyProperty); }
set { SetValue(MyEnumProperyProperty, value); }
}
public static readonly DependencyProperty MyEnumProperyProperty = DependencyProperty.Register("MyEnumPropery", typeof(MyEnum), typeof(MyBorderBehavior), new PropertyMetadata(PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dO, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var self = dO as MyBorderBehavior;
if (self != null && self._controlToColorBorder != null)
self.SetColor();
}
private Control _controlToColorBorder;
private void SetColor()
{
switch (this.MyEnumPropery)
{
case MyEnum.One:
this._controlToColorBorder.BorderBrush = Brushes.Yellow;
break;
case MyEnum.Two:
this._controlToColorBorder.BorderBrush = Brushes.Red;
break;
case MyEnum.Three:
this._controlToColorBorder.BorderBrush = Brushes.Green;
break;
case MyEnum.Four:
this._controlToColorBorder.BorderBrush = Brushes.DeepPink;
break;
}
}
protected override void OnAttached()
{
this._controlToColorBorder = this.AssociatedObject;
this._controlToColorBorder.Loaded += ControlToColorBorderLoaded;
base.OnAttached();
}
private void ControlToColorBorderLoaded(object sender, RoutedEventArgs e)
{
this.SetColor();
}
}
Notes:
As you can see, you have to use the
System.Windows.Interactivity-Assembly
This little Behavior can applied to everything of type Control
(Since Control has BorderBrush-Property)
I've implemented a DependencyProperty to make things bindable.
Four your purpose, you sure have to replace MyEnum with yours and
adjust the colors. Furthermore, you might have to implement another
DependencyProperty to bring your 2nd condition to the Behavior.
Hope this gives you a clue, on how you can get ahead with your code.
I'm trying to build a small navigation system in my WPF application. I'm using this tutorial to navigate between pages. I want to add 'Go back' functionality on top of it for one UserControl.
I have a UserControl Orders and another UserControl Order. Orders is shown in MainWindow and when I click on an button, Order UserControl should be shown in the same place in MainWindow. I tried to put a reference to the Orders usercontrol in the Order usercontrol and navigate to the Orders through Order. But the Order isn't destroyed since I'm using a variable from that class.
How can I make sure that when I navigate to Order form Orders, the Orders isn't destroyed and when I navigate to Orders from Order, Order is destroyed.
Button click event handler in Orders Class:
private void ShowOrder(object sender, RoutedEventArgs e)
{
Order order = new Order();
Switcher.Switch(order);
}
Return back button click handler in Order Class
public UserControl parent;
private void ReturnBack(object sender, RoutedEventArgs e)
{
Switcher.Switch(parent);
}
I usually do the next pattern whice uses ControlTemplate, lets say you have in your class:
private Enums.View _currView;
public Enums.View CurrView
{
get
{
return _currView;
}
set
{
_currView = value;
OnPropertyChanged("CurrView");
}
}
When Enums.View is:
public enum View
{
ViewA = 1,
ViewB = 2,
ViewC = 3,
}
Then, using Binding to CurrView above we change the view when it changes:
<UserControl ...
xmlns:Views="clr-namespace:CustomersManager.View"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<!--*********** Control templates ***********-->
<ControlTemplate x:Key="DefultTemplate">
<Views:DefultCustomersView/>
</ControlTemplate>
<ControlTemplate x:Key="A">
<Views:ViewAllCustomersView />
</ControlTemplate>
<ControlTemplate x:Key="B">
<Views:AddNewCustomersView />
</ControlTemplate>
<ControlTemplate x:Key="C">
<Views:EditCustomersView />
</ControlTemplate>
</UserControl.Resources>
<Border BorderBrush="Gray" BorderThickness="2">
<Grid>
<ContentControl DataContext="{Binding}" >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{StaticResource DefultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CurrView}" Value="ViewA">
<Setter Property="Template" Value="{StaticResource A}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrView}" Value="ViewB">
<Setter Property="Template" Value="{StaticResource B}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrView}" Value="ViewC">
<Setter Property="Template" Value="{StaticResource C}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl >
</Grid>
</Border>
</UserControl>
I have simple custom control that shows a message to user (something like browser's Info bar).
I have added a Boolean Dependency Property that indicate an error message. If flag is set the background color of control should be red otherwise yellow.
Here is style for the control(in Themes\Generic.xaml):
<Style TargetType="{x:Type local:InfoBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:InfoBar}">
<ControlTemplate.Triggers>
<Trigger Property="IsError" Value="True" >
<Setter Property="Background" Value="LightPink" />
</Trigger>
<Trigger Property="IsError" Value="False" >
<Setter Property="Background" Value="LightYellow" />
</Trigger>
</ControlTemplate.Triggers>
<Grid Margin="4,0,4,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{TemplateBinding Message}" Padding="5" FontWeight="Normal" TextWrapping="Wrap" Grid.Column="0"/>
<Button x:Name="PART_CloseButton" Grid.Column="1" VerticalAlignment="Top" >
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Transparent">
<Image Height="16" Width="16" Source="/QOffice.Common.Controls;component/Images/icons/Close.png" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is The control itself:
[TemplatePart(Name = PART_CloseButton, Type = typeof(ButtonBase))]
public class InfoBar : Control
{
private const string PART_CloseButton = "PART_CloseButton";
static InfoBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(InfoBar), new FrameworkPropertyMetadata(typeof(InfoBar)));
}
#region CloseButton
private ButtonBase _closeButton;
/// <summary>
/// Gets or sets the CloseButton template part.
/// </summary>
private ButtonBase CloseButton
{
get
{
return _closeButton;
}
set
{
if (_closeButton != null)
{
_closeButton.Click -= OnButtonClick;
}
_closeButton = value;
if (_closeButton != null)
{
_closeButton.Click += OnButtonClick;
}
}
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
this.Visibility = System.Windows.Visibility.Collapsed;
}
#endregion
public override void OnApplyTemplate()
{
CloseButton = GetTemplateChild(PART_CloseButton) as ButtonBase;
}
#region DependencyProperty Message of InfoBar
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(InfoBar),
new UIPropertyMetadata());
#endregion
#region DependencyProperty IsError of InfoBar
public bool IsError
{
get { return (bool)GetValue(IsErrorProperty); }
set { SetValue(IsErrorProperty, value); }
}
public static readonly DependencyProperty IsErrorProperty =
DependencyProperty.Register("IsError", typeof(bool), typeof(InfoBar),
new UIPropertyMetadata());
#endregion
}
As you can see I have defined a property IsError and a trigger to set the background of the control.
But the background is always transparent. Other than that the control if functional.
What is wrong?
It seems that your Custom Control is not setting Background Color properly even if I add Background color manually. I am not sure why this is, hopefully someone can elaborate. I did fix your issue though by changing the color of the Grid in your style using:
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:InfoBar}}, Path=IsError}" Value="True">
<Setter Property="Background" Value="LightPink" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:InfoBar}}, Path=IsError}" Value="False">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
This triggers the background color of the grid based on the IsError value in your InfoBar control.
You give your Control a Background but no child is using it. Two possible solutions:
TemplateBinding
<Grid Margin="4,0,4,0" Background="{TemplateBinding Background}">
DataTrigger with TargetName
<ControlTemplate TargetType="{x:Type local:InfoBar}">
<Grid Name="grid" Margin="4,0,4,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
...
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsError" Value="True" >
<Setter TargetName="grid" Property="Background" Value="LightPink" />
</Trigger>
<Trigger Property="IsError" Value="False" >
<Setter TargetName="grid" Property="Background" Value="LightYellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
In this solution you have to change the order: ControlTemplate.Triggers after Grid declaration.
Try this (Since IsError is DP in your InfoBar and not property of your ControlTemplate)
<DataTrigger Property="{Binding IsError, RelativeSource={RelativeSource
Mode=TemplatedParent}" Value="True">
<Setter Property="Background" Value="LightPink" />
</DataTrigger>
<DataTrigger Property="{Binding IsError, RelativeSource={RelativeSource
Mode=TemplatedParent}" Value="False">
<Setter Property="Background" Value="LightYellow" />
</DataTrigger>