I have a password box, but i also have a textblock as hint text within the control template. I'd like this to be removed when the password box has a value. I have tried this below but it doesn't work, how can I do this?
Simplified XAML :
<PasswordBox Height="20" Name="pwdBox" PasswordChanged="pwdBox_PasswordChanged" Style="{DynamicResource PasswordBoxStyle1}"/>
<Style x:Key="PasswordBoxStyle1" TargetType="{x:Type PasswordBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Border x:Name="Border" .. >
<StackPanel ..>
<TextBlock x:Name="LabelTextBlock" ...
Text="Password Label" />
<Grid>
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
<TextBlock x:Name="HintTextBlock"
Focusable="False"
IsHitTestVisible="False"
Opacity="0"
Text="Enter Your Password" />
</Grid>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code Behind :
private void pwdBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (pwdBox.SecurePassword.Length == 0)
{
HintTextBlock.IsVisible = true;
}
else
{
HintTextBlock.IsVisible = false;
}
}
It says that the name 'HintTextBlock does not exist in the current context'
Since, the text box HintTextBlock is part of Template of PassworkBox so it can not accessed directly as it is not part of direct control of window. Use the FindName to find the control in template of passwordbox.
TextBlock hintTextBlock = pwdBox.Template.FindName("HintTextBlock", pwdBox) as TextBlock;
if (pwdBox.SecurePassword.Length == 0)
{
hintTextBlock.Visiblility = Visiblitity.Visible;
}
else
{
hintTextBlock.Visiblility = Visiblility.Collapsed;
}
Related
I merged the things I have found out to implement an auto-scroll-to-end Headered Items Control. I cannot manage to do it. What am I doing wrong?
In Resource Directory, ScrollingHeaderedItemsControl is styled as:
<Style TargetType="common:ScrollingHeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="3" SnapsToDevicePixels="True">
<StackPanel>
<Grid>
<Rectangle Fill="{TemplateBinding Background}"/>
<ContentPresenter ContentSource="Header" Margin="2,0,0,0"/>
</Grid>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<ItemsPresenter Margin="5,0,0,0"/>
</ScrollViewer>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The class ScrollingHeaderedItemsControl is defined as here:
public class ScrollingHeaderedItemsControl : HeaderedItemsControl
{
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
int newItemCount = e.NewItems.Count;
if (newItemCount > 0)
this.ScrollToEnd();
base.OnItemsChanged(e);
}
}
}
ScrollToEnd is a static function written specifically for ScrollingHeaderedItemsControl such as:
public static void ScrollToEnd(this ItemsControl control)
{
try
{
Border border = VisualTreeHelper.GetChild((DependencyObject)control, 0) as Border;
StackPanel sp = VisualTreeHelper.GetChild((DependencyObject)border, 0) as StackPanel;
ScrollViewer sv = VisualTreeHelper.GetChild((DependencyObject)sp, 1) as ScrollViewer;
sv.ScrollToEnd();
}
catch(Exception)
{
}
}
ScrollingHeaderedItemsControl is used in the UserControl like this:
<common:ScrollingHeaderedItemsControl x:Name="MessagesHIC" FontSize="32" Header="Error/Warning/Info Messages"
Background="Green"
BorderBrush="AntiqueWhite" ItemsSource="{Binding Messages}"
Margin="10" Grid.Row="1" Grid.Column="0"
ScrollViewer.CanContentScroll="True">
<common:ScrollingHeaderedItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MessageString}" Foreground="{Binding MessageColor}" TextWrapping="Wrap" FontWeight="Light" FontSize="26" />
</DataTemplate>
</common:ScrollingHeaderedItemsControl.ItemTemplate
</common:ScrollingHeaderedItemsControl>
Your template contains a stackpanel which doesn't set a height constraint, therefore the scrollviewer is never required to show the scrollbars. Change your Template to the following:
<Style TargetType="common:ScrollingHeaderedItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="3" SnapsToDevicePixels="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid>
<Rectangle Fill="{TemplateBinding Background}" />
<ContentPresenter ContentSource="Header" Margin="2,0,0,0" />
</Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
<ItemsPresenter Margin="5,0,0,0" />
</ScrollViewer>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You will then need to change your code behind to:
try
{
Border border = VisualTreeHelper.GetChild((DependencyObject)control, 0) as Border;
Grid sp = VisualTreeHelper.GetChild((DependencyObject)border, 0) as Grid;
ScrollViewer sv = VisualTreeHelper.GetChild((DependencyObject)sp, 1) as ScrollViewer;
sv.ScrollToEnd();
}
catch (Exception)
{
}
I have a TreeviewItem with a style set to this
<Style x:Key="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<StackPanel x:Name="stackpanel" Orientation="Horizontal">
<CheckBox x:Name="checkbox_treeview" Checked="treeView_AfterCheck" Unchecked="treeView_AfterCheck"/>
<Image x:Name="image_treeview" Width="16"/>
<local:WPFEditableTextBlock x:Name="label_TreeView" Text="{TemplateBinding Header}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am able to access the checkbox of the template by doing this
TreeViewItem folderNode = new TreeViewItem();
Style style = this.FindResource("TreeViewItemStyle") as Style;
folderNode.Style = style;
ControlTemplate controlTemplate = folderNode.Template;
var templatedControl = folderNode.Template.LoadContent() as FrameworkElement;
CheckBox chbx = (CheckBox)templatedControl.FindName("checkbox_treeview");
once I am able to access this checkbox I have it go to the checked event handler. within that I want to be able to access the treeViewItem that contains that checkbox, but I can't figure out how to do this. Please help me out!!!
To access the treeViewItem from the checkbox defined in the template you could pass it in the Tag property from xaml like so:
<ControlTemplate TargetType="TreeViewItem">
<StackPanel x:Name="stackpanel" Orientation="Horizontal">
<CheckBox x:Name="checkbox_treeview" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}" Checked="treeView_AfterCheck" Unchecked="treeView_AfterCheck"/>
<Image x:Name="image_treeview" Width="16"/>
<local:WPFEditableTextBlock x:Name="label_TreeView" Text="{TemplateBinding Header}"/>
</StackPanel>
</ControlTemplate>
and here how to retrieve it from the event handler:
private void treeView_AfterCheck(object sender, RoutedEventArgs e)
{
var tvi = ((sender as CheckBox).Tag as TreeViewItem);
}
I declare a style in xaml that I need to use and apply to a user control in code behind and when I use the same style twice the following error throws:
Element already has a logical parent. It must be detached from the old
parent before it is attached to a new one.
What am I doing wrong? I need to create multiple controls of the same user-control-type in code behind and apply one and the same Style to it.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
xmlns:s="http://schemas.abtsoftware.co.uk/scichart"
x:Class="MyChartControl.MainWindow"
Title="MainWindow" Height="655" Width="1020">
<Window.Resources>
<Style x:Key="SciChartSurfaceStyle" TargetType="{x:Type s:SciChartSurface}">
<Setter Property="XAxis">
<Setter.Value>
<s:DateTimeAxis Visibility="Visible"
TextFormatting="dd/MM/yyyy"
SubDayTextFormatting="dd/MM/yyyy HH:mm:ss.fff"
GrowBy="0.02, 0.02"/>
</Setter.Value>
</Setter>
<Setter Property="YAxis">
<Setter.Value>
<s:NumericAxis AxisAlignment="Right"
Visibility="Visible"
TextFormatting="{Binding YAxisFormatting}"
GrowBy="0.02, 0.02"
AutoRange="Always"/>
</Setter.Value>
</Setter>
<Setter Property="ChartModifier">
<Setter.Value>
<s:ModifierGroup>
<s:RubberBandXyZoomModifier IsAnimated = "False" IsXAxisOnly = "True" ExecuteOn = "MouseRightButton"/>
<s:ZoomPanModifier XyDirection="XYDirection" ClipModeX = "ClipAtExtents" ExecuteOn ="MouseLeftButton" />
<s:MouseWheelZoomModifier XyDirection = "XYDirection"/>
<s:ZoomExtentsModifier IsAnimated = "False" ExecuteOn = "MouseDoubleClick" />
<s:XAxisDragModifier DragMode = "Scale"/>
<s:CursorModifier SourceMode="AllSeries" UseInterpolation="True"/>
<s:LegendModifier ShowLegend="True" LegendPlacement ="Inside" GetLegendDataFor="AllSeries" Margin="10"/>
<!--<s:SeriesSelectionModifier ReceiveHandledEvents="True">
<s:SeriesSelectionModifier.SelectedSeriesStyle>
<Style TargetType="s:BaseRenderableSeries">
<Setter Property="SeriesColor" Value="White"/>
<Setter Property="PointMarkerTemplate">
<Setter.Value>
<ControlTemplate>
<s:EllipsePointMarker Fill="#FF00DC" Stroke="White" Width="7" Height="7"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</s:SeriesSelectionModifier.SelectedSeriesStyle>
</s:SeriesSelectionModifier>-->
</s:ModifierGroup>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="Black">
<TextBlock Text="Dataseries Type:" Margin="5,0" VerticalAlignment="Center" FontSize="12" Foreground="White"/>
<ComboBox x:Name="ComboBox_ChooseSeriesType" MinWidth="140" Margin="5,3" VerticalContentAlignment="Center"/>
<TextBlock Text="Theme:" Margin="5,0" VerticalAlignment="Center" FontSize="12" Foreground="White"/>
<ComboBox x:Name="ComboBox_ChooseTheme" MinWidth="140" Margin="5,3" VerticalContentAlignment="Center"/>
</StackPanel>
<dxdo:LayoutGroup Grid.Row="1" x:Name="LayoutGroup" Orientation="Vertical">
<!--<dxdo:LayoutPanel Name="Panel1">
<s:SciChartSurface Name="Surface1" Style="{StaticResource SciChartSurfaceStyle}"></s:SciChartSurface>
</dxdo:LayoutPanel>-->
</dxdo:LayoutGroup>
</Grid>
And the code-behind method that retrieves the style and applies it:
private void TestSomeStuff()
{
var style = this.TryFindResource("SciChartSurfaceStyle") as Style;
var sciChartSurface1 = new SciChartSurface() {Style = style};
var panel1 = new LayoutPanel(){Content=sciChartSurface1};
var style2 = this.TryFindResource("SciChartSurfaceStyle") as Style;
var sciChartSurface2 = new SciChartSurface() {Style = style2};
var panel2 = new LayoutPanel() {Content = sciChartSurface2};
LayoutGroup.Add(panel1);
LayoutGroup.Add(panel2);
}
EDIT
Adding panel1 to LayoutGroup works just fine but the run-time error occurs as soon as I attempt to add panel2. Also, as long as do not inject style into a new instance of SciChartSurface it works just fine. The error pops up as soon as I inject the style into both new surfaces.
Do not set Style in code behind directly:
var style = this.TryFindResource("SciChartSurfaceStyle") as Style;
var sciChartSurface1 = new SciChartSurface() {Style = style};
but with SetValue method:
var style = this.TryFindResource("SciChartSurfaceStyle") as Style;
var sciChartSurface1 = new SciChartSurface();
sciChartSurface1.SetValue(StyleProperty, style);
I have a xaml code for Button declared as ControlTemplate
App.xaml
<!--Style for button start here-->
<Style x:Key="myButtonStyle" TargetType="Border">
<EventSetter Event="Border.MouseLeftButtonDown" Handler="ButtonDown" />
<EventSetter Event="Border.MouseLeftButtonUp" Handler="ButtonUp" />
<EventSetter Event="Border.MouseEnter" Handler="ButtonEnter" />
<EventSetter Event="Border.MouseLeave" Handler="ButtonLeave"/>
</Style>
<!--Style for myButtonStyle ends here-->
<!--Control Template for button start here-->
<ControlTemplate TargetType="Button" x:Key="buttonPrimary">
<Grid Width="{TemplateBinding Width}">
<Border Height="35" Width="{TemplateBinding Width}" Style="{StaticResource myButtonStyle}" Background="{TemplateBinding Background}" CornerRadius="3" Loaded="borderLoaded" x:Name="myButton">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" >
<TextBlock.Foreground>
White
</TextBlock.Foreground>
<TextBlock.FontSize>14</TextBlock.FontSize>
</ContentPresenter>
</Border>
</Grid>
</ControlTemplate>
And In another file I have handled all mouse event ..
Main.cs
private void ButtonDown(object sender, RoutedEventArgs e)
{
Console.WriteLine("ButtonDown");
}//Button Down method ends here
private void ButtonUp(object sender, RoutedEventArgs e)
{
Console.WriteLine("Button Up");
}//ButtonUp method ends here
private void ButtonLeave(object sender, RoutedEventArgs e)
{
Console.WriteLine("ButtonLeave");
}
private void ButtonEnter(object sender, RoutedEventArgs e)
{
Console.WriteLine("ButtonEnter");
}
In main.xaml I am calling these button..
Main.xaml
<Button Content="ButtonPrimary" Width="110" Background="#428bca" Template="{StaticResource buttonPrimary}" />
All the event are firing except MouseLeftButtonUp ..??
The Button's click event eats MouseUp events.
So:
<Style x:Key="buttonPrimary" TargetType="Button">
<EventSetter Event="Click" Handler="ButtonBase_OnClick"/>
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ButtonDown" />
<EventSetter Event="PreviewMouseLeftButtonUp" Handler="ButtonUp" />
<EventSetter Event="MouseEnter" Handler="ButtonEnter" />
<EventSetter Event="MouseLeave" Handler="ButtonLeave"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Width="{TemplateBinding Width}">
<Border Height="35" Width="{TemplateBinding Width}" Background="{TemplateBinding Background}" CornerRadius="3" x:Name="myButton">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" >
<TextBlock.Foreground>
White
</TextBlock.Foreground>
<TextBlock.FontSize>14</TextBlock.FontSize>
</ContentPresenter>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then add the ButtonBase_OnClick event that just handles the click event:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e){
e.Handled = true;
}
And Change your Button from Template= to Style= then you will get all your events.
So I'm at a loss to understand this. I have a custom control that uses up/down buttons to increase/decrease the time as displayed on toggle buttons. I have the Content property of the Toggles displaying the correct values of the Hour and Minute properties, and I'm now trying to set up the code-behind to increase the values. According to the VS2010 debugger, it is increasing the value of the Hour property, but it's not changing the content of the Toggles to reflect this. I have the binding mode set to TwoWay, and I'm using {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Hour, Mode=TwoWay} to bind to the value as this is within the generic.xaml file of the custom control. Any ideas on how to make the displayed value update correctly?
XAML: (Style templates removed to save space)
<Style TargetType="{x:Type local:TimePicker}">
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height}" />
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="Transparent"
BorderThickness="1">
<StackPanel x:Name="PART_Root"
Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="{TemplateBinding VerticalAlignment}">
<!--Region Hour Button-->
<ToggleButton x:Name="PART_Hour"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Margin="0"
BorderBrush="Transparent"
BorderThickness="0"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Hour, Mode=TwoWay, BindsDirectlyToSource=True}">
</ToggleButton>
<!--EndRegion-->
<Label HorizontalContentAlignment="{TemplateBinding HorizontalAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalAlignment}"
FontSize="14"
Content=":"/>
<!--Region Minute Button-->
<ToggleButton x:Name="PART_Minute"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Margin="0"
BorderBrush="Transparent"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Minute}">
</ToggleButton>
<!--EndRegion-->
<StackPanel x:Name="PART_IncDecPanel"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical">
<Grid Height="{Binding ElementName=PART_Hour, Path=ActualHeight}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Viewbox Stretch="Fill" Grid.Row="0">
<!--Region Increase Button-->
<Button x:Name="PART_IncreaseTime"
HorizontalContentAlignment="{TemplateBinding HorizontalAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalAlignment}"
BorderBrush="Transparent"
BorderThickness="0"
FontFamily="Marlett"
Foreground="DimGray"
Content="5"
Padding="0"
Click="PART_IncreaseTime_Click">
</Button>
<!--EndRegion-->
</Viewbox >
<Viewbox Stretch="Fill" Grid.Row="1">
<!--Region Decrease Button-->
<Button x:Name="PART_DecreaseTime"
HorizontalContentAlignment="{TemplateBinding HorizontalAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalAlignment}"
BorderBrush="Transparent"
BorderThickness="0"
FontFamily="Marlett"
Foreground="DimGray"
Content="6"
Padding="0">
</Button>
<!--EndRegion-->
</Viewbox>
</Grid>
</StackPanel>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code:
public class TimePicker : Control
{
#region Dependency Property Declarations
public static DependencyProperty HourProperty = DependencyProperty.Register("Hour", typeof(int), typeof(TimePicker),
new FrameworkPropertyMetadata((int)12, new PropertyChangedCallback(OnHourChanged)));
public static DependencyProperty MinuteProperty = DependencyProperty.Register("Minute", typeof(string), typeof(TimePicker),
new FrameworkPropertyMetadata((string)"00", new PropertyChangedCallback(OnMinuteChanged)));
#endregion
#region Properties
public int Hour
{
get { return (int)GetValue(HourProperty); }
set { SetValue(HourProperty, value); }
}
public string Minute
{
get { return (string)GetValue(MinuteProperty); }
set { SetValue(MinuteProperty, value); }
}
#endregion
#region Events
private static void OnHourChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
TimePicker time = new TimePicker();
time.Hour = (int)e.NewValue;
MessageBox.Show("Hour changed");
}
private static void OnMinuteChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
}
#endregion
static TimePicker()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TimePicker), new FrameworkPropertyMetadata(typeof(TimePicker)));
}
}
public partial class TimePickerEvents : ResourceDictionary
{
TimePicker time = new TimePicker();
void PART_IncreaseTime_Click(object sender, RoutedEventArgs e)
{
time.Hour += 1;
}
}
Not sure why you are using a Togglebutton to display the hour/minutes, I would think a Label/TextBlock would be better suited for that.
Change the binding of your ToggleButtons to
Content="{TemplateBinding Hour}"
Then in the code, override OnApplyTemplate as such
public override void OnApplyTemplate()
{
var upButton = GetTemplateChild("PART_IncreaseTime") as Button;
upButton.Click += IncreaseClick;
var downButton = GetTemplateChild("PART_DecreaseTime") as Button;
downButton.Click += DecreaseClick;
}
private void IncreaseClick(object sender, RoutedEventArgs e)
{
// Here would be a place to see what toggle button is checked
// (or which TextBlock last had focus) and increase Hour/Minute
// based on that info
Hour += 1;
}
private void DecreaseClick(object sender, RoutedEventArgs e)
{
// Here would be a place to see what toggle button is checked
// (or which TextBlock last had focus) and decreaseHour/Minute
// based on that info
Hour -= 1;
}
This should get you started.
FYI: Within your OnHourChanged and OnMinuteChanged the sender is your control (TimePicker). So you can cast the sender to TimePicker and access all of your properties. Even your private properties.
Why don't you use the WPF toolkit's numerical up down control?
http://wpftoolkit.codeplex.com/wikipage?title=NumericUpDown
All you have to do is bind it to your properties two way.