Fixed text in TextBox - c#

How can I dynamically add fixed text to a TextBox? By "fixed text", I mean text which can't be deleted by the user's input.
For example, the path in CMD:
C:\Program Files>cd ..
C:\>

I'm assuming that you want an editable textbox, that has some fixed text at the start of it that the user cannot edit. If so then this seems to work - it's based on the standard textbox style as extracted in Blend...
You need to have the following namespace declaration in your xaml root:
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
Then use this template:
<ControlTemplate TargetType="{x:Type TextBox}">
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">This is fixed:</TextBlock>
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</StackPanel>
</Microsoft_Windows_Themes:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
If you were to wrap this in a custom control or user control, you could programmatically set the fixed text through a custom property.

TextBox IsReadOnly = true when you populate the text dynamically? if you use MVVM bind IsReadOnly to a property in your ViewModel, when that ViewModel populates the text

You can use a textblock instead.
If You have to use a textbox, you can do it Read Only changing the IsReadOnly property to "True"

private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (textBox1.SelectionStart < LengthOfFixedString)
e.SuppressKeyPress = true;
}

Related

Removing full screen in xaml dynamically

This will probably be very simple for most of you, I am new to XAML and WPF.
I have an app that startes att full screen, I did this by adding
WindowState="Maximized"
WindowStyle="None"
I want to have a button that simply eliminates this part. I have a "Full screen" button in the xaml and by click he is calling a "FullScreen_Click" function in my code.
I just need to know what to write in the code that will eliminate the full screen if it is on full screen mode and restore it to full screen when it is not.
Try this:
private void FullScreen_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
This will toggle between WindowState.Maximized and WindowState.Normal each time the Button is clicked.
For a xaml only technique just for reference to see a xaml example in comparison (but I would do #mm8's route, it's simpler);
1. Bind your property to that of another like:
<Window WindowState="{Binding Tag, ElementName=toggleState}" .... />
2. Use a `ToggleButton` or similar control and `Triggers`
.
<!-- like this PoC -->
<Grid>
<Grid.Resources>
<Style x:Key="cwWindowState_PoC" TargetType="{x:Type ToggleButton}">
<Setter Property="Tag" Value="Maximized"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border Background="{TemplateBinding Background}"/>
<ContentPresenter x:Name="MyContentPresenter"
Content="{TemplateBinding Tag}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Tag" Value="Normal" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Tag" Value="Maximized" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ToggleButton x:Name="toggleState" Content="Click Me"
Background="Green"
Style="{StaticResource cwWindowState_PoC}"/>
</Grid>
Could also use DataTrigger but that requires interaction triggers instead of just a property setter from a template.

Custom DependencyProperty in style triggers using TemplateBinding

I'm having an issue getting the following to work. I have created a subclass of button with several DependencyProperties. and we are attempting to use these in the style.
We have the following c#
/// <summary>
/// Custom Is Mouse Over Colour.
/// </summary>
public static DependencyProperty LITIsMouseOverProperty =
DependencyProperty.RegisterAttached("LITIsMouseOver",
typeof(System.Windows.Media.LinearGradientBrush), typeof(Button));
public static System.Windows.Media.LinearGradientBrush GetLITIsMouseOver(DependencyObject target)
{
return (System.Windows.Media.LinearGradientBrush)target.GetValue(LITIsMouseOverProperty);
}
public static void SetLITIsMouseOver(DependencyObject target, System.Windows.Media.LinearGradientBrush value)
{
target.SetValue(LITIsMouseOverProperty, value);
}
and the following XAML:
<Style x:Key="StandardButton" TargetType="{x:Type Utils:LITCustomButton01}">
<Setter Property="LITIsMouseOver" Value="{StaticResource DarkBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Utils:LITCustomButton01}">
<Border x:Name="buttonBorder" CornerRadius="{TemplateBinding LITCornerRadius}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<TextBlock Name="textBlock" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{TemplateBinding LITIsMouseOver}" />
</Trigger>
</Style.Triggers>
</Style>
We have this same system working on corner radius, using the following:
/// <summary>
/// Custom Corner Radius
/// </summary>
public static DependencyProperty LITCornerRadiusProperty =
DependencyProperty.RegisterAttached("LITCornerRadius",
typeof(CornerRadius), typeof(Button));
public static CornerRadius GetLITCornerRadius(DependencyObject target)
{
return (CornerRadius)target.GetValue(LITCornerRadiusProperty);
}
public static void SetLITCornerRadius(DependencyObject target, CornerRadius value)
{
target.SetValue(LITCornerRadiusProperty, value);
}
However, the background throws the following error:
"member is not valid because it does not have a qualifying type name."
TemplateBinding can only be used in a ControlTemplate. The TemplateBinding shortcut does not work in triggers so you will have to use the RelativeSource binding. When overriding the ControlTemplate you will need to specify the target of the trigger. Something like this:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
TargetName="buttonBorder"
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LITIsMouseOver}"/>
</Trigger>
</ControlTemplate.Triggers>
Also, you are creating an attached property which would allow you to do:
<Grid Utils:LITCustomButton01.LITIsMouseOver="Pink"/>
In this case, nothing will happen on MouseOver. You want to use Register as opposed to RegisterAttached.

How do I prevent WPF buttons from remaining highlighted after being clicked?

When a standard WPF button is clicked, it gets highlighted in blue (probably using the blue color from whatever Windows theme is set), and it stays highlighted until you interact with any other control. For my application, it is confusing for the user.
Is there a simple way turn this off and get the button back to its normal style?
I am using .NET 4.
What happens is that the button accepts the input focus after it has been clicked, just like any other control does when you click on it.
And the way that Windows indicates that a control has the input focus (at least under the Aero theme) is with a subtle blue highlight.
For a button control in particular, when it has the input focus, simply pressing the Enter key will "push" that button. That's why maintaining the highlight is very important, so that the user knows what to expect.
The better solution is to set the focus to a different control in your window immediately after the user has clicked on the button. That way, it will no longer be automatically highlighted and no action will be automatically triggered when the user presses the Enter key. (This is the real usability problem that you're trying to solve, even if you don't know it yet. Nothing is more confusing than a button inadvertently getting clicked when the user is actually trying to type something.)
You could prevent the button from ever getting the focus altogether by setting its Focusable property to false, but I would very much recommend against this. Once you've done this, there will be no way for the user to "press" the button using only the keyboard. Well-designed applications should always be accessible to users who either prefer not to or who are unable to use the mouse.
Try to set Focusable to false. The button will be clickable but will not remain focused.
This is the default look for Aero buttons when they have focus. You can either set Focusable="False" or use a custom Style, that doesn't render it differently when the button has focus. Something like:
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
<Style x:Key="BaseButtonStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<theme:ButtonChrome Name="Chrome" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding Button.IsDefaulted}"
RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"
SnapsToDevicePixels="true">
<ContentPresenter Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</theme:ButtonChrome>
<ControlTemplate.Triggers>
<!--
Do not show blue when focused
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter TargetName="Chrome" Property="RenderDefaulted" Value="true" />
</Trigger>-->
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Chrome" Property="RenderPressed" Value="true" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}" TargetType="{x:Type ToggleButton}" />
<Style x:Key="{x:Type RepeatButton}" BasedOn="{StaticResource BaseButtonStyle}" TargetType="{x:Type RepeatButton}" />
<Style x:Key="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}" TargetType="{x:Type Button}" />
You'd need to add a reference to PresentationFramework.Aero.dll
That is simply the focussed state. To turn it off you will have to change the focussed state. It's easiest by using Blend.
I do not recommend setting Focusable to false because it interferes with using the keyboard
<Style x:Key="TouchButton" TargetType="{x:Type Button}">
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="ClickMode" Value="Press"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border" CornerRadius="2" BorderThickness="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="Red"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I needed to do something similar, but in code at runtime, it looked like this
//You can get this XAML by using System.Windows.Markup.XamlWriter.Save(yourButton.Template)";
const string controlXaml = "<ControlTemplate TargetType=\"ButtonBase\" " +
"xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" " +
"xmlns:s=\"clr-namespace:System;assembly=mscorlib\" " +
"xmlns:mwt=\"clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero\">" +
"<mwt:ButtonChrome Background=\"{TemplateBinding Panel.Background}\" " +
"BorderBrush=\"{TemplateBinding Border.BorderBrush}\" " +
"RenderDefaulted=\"{TemplateBinding Button.IsDefaulted}\" " +
//"RenderMouseOver=\"{TemplateBinding UIElement.IsMouseOver}\" " +
"RenderPressed=\"{TemplateBinding ButtonBase.IsPressed}\" Name=\"Chrome\" SnapsToDevicePixels=\"True\">" +
"<ContentPresenter RecognizesAccessKey=\"True\" " +
"Content=\"{TemplateBinding ContentControl.Content}\" " +
"ContentTemplate=\"{TemplateBinding ContentControl.ContentTemplate}\" " +
"ContentStringFormat=\"{TemplateBinding ContentControl.ContentStringFormat}\" " +
"Margin=\"{TemplateBinding Control.Padding}\" " +
"HorizontalAlignment=\"{TemplateBinding Control.HorizontalContentAlignment}\" " +
"VerticalAlignment=\"{TemplateBinding Control.VerticalContentAlignment}\" " +
"SnapsToDevicePixels=\"{TemplateBinding UIElement.SnapsToDevicePixels}\" /></mwt:ButtonChrome>" +
"<ControlTemplate.Triggers>" +
"<Trigger Property=\"UIElement.IsKeyboardFocused\">" +
"<Setter Property=\"mwt:ButtonChrome.RenderDefaulted\" TargetName=\"Chrome\"><Setter.Value><s:Boolean>True</s:Boolean></Setter.Value></Setter>" +
"<Trigger.Value><s:Boolean>True</s:Boolean></Trigger.Value></Trigger>" +
"<Trigger Property=\"ToggleButton.IsChecked\">" +
"<Setter Property=\"mwt:ButtonChrome.RenderPressed\" TargetName=\"Chrome\"><Setter.Value><s:Boolean>True</s:Boolean></Setter.Value></Setter>" +
"<Trigger.Value><s:Boolean>True</s:Boolean></Trigger.Value></Trigger>" +
"<Trigger Property=\"UIElement.IsEnabled\"><Setter Property=\"TextElement.Foreground\"><Setter.Value><SolidColorBrush>#FFADADAD</SolidColorBrush></Setter.Value></Setter>" +
"<Trigger.Value><s:Boolean>False</s:Boolean></Trigger.Value></Trigger></ControlTemplate.Triggers>" +
"</ControlTemplate>";
var xamlStream = new MemoryStream(System.Text.Encoding.Default.GetBytes(controlXaml));
var _buttonControlTemplate = (ControlTemplate)System.Windows.Markup.XamlReader.Load(xamlStream);
var yourButton = new Button() { Template = _buttonControlTemplate };
You can see that i comment the ""RenderMouseOver" line
My first hope was using FrameworkElementFactory but i needed to create all the default template.... ALL BY HAND! ;)
Using
System.Windows.Markup.XamlWriter.Save(myButton.Template)
It give me the template i wanted and then removing the Render section was easy.
I found 2 steps solution. The solution is little funny but working .
My referance posts are;
How to remove global FocusVisualStyle to all the Controls?
and
C# WPF application .NET 4.5 Set Mouse Position
One DLL must be imported , because WPF is not directly supporting mouse cursor move.
add System.Runtime.InteropServices to namespace
Add two line to the MainWindow or whatever your window's code
[DllImport("User32.dll")]
private static extern bool SetCursorPos(int X, int Y);
Add these 2 lines to your click event .
SetCursorPos(0, 0);
ButtonName.FocusVisualStyle = null;
It works for me .
I've resolved this situation, in my case, by using MultiTrigger, and to set the states like this:
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="True"/>
<Condition Property="IsPressed" Value="False"/>
</MultiTrigger.Conditions>
TO more information see this link.

A read-only CheckBox in C# WPF

I am having a tricky problem, I want some slightly unusual behaviour from a checkbox and can't seem to figure it out. Any suggestions would be most welcome. The behaviour I want is:
The CheckBox is enabled and ready for the user to click, IsChecked represents a bound boolean value stored in a data structure
The user clicks the CheckBox causing the click event to fire but the bound value in the data structure is NOT updated and the visual representation of the CheckBox is NOT updated but it is disabled to stop further clicking
The click event triggers a message to be sent to a remote device which takes some time to respond
The remote device responds causing the data structure to be updated with the new value, the binding then updates the isChecked status and the CheckBox gets reenabled for further clicking
The problem I have is that although a OneWay data binding works at not updating the data structure when the CheckBox is clicked, the visual representation does change (which I think is odd, shouldn't IsChecked now act like a pointer to the value in the data structure).
I can reverse the change in the Click() event and do the disable there as well but this is pretty messy. I can also have the set property of the data structure value to set an isEnabled value which is also bound to reenable the CheckBox but that seems messy too.
Is there a clean way to do this? Perhaps with a derived CheckBox class? How can I stop the visual representation getting updated?
Thanks
Ed
What about data binding to the IsHitTestVisible property?
For example, assuming an MVVM approach:
Add a IsReadOnly property to your view model, initially set as true to allow click.
Binding this property to CheckBox.IsHitTestVisible.
After the first click, update your view model to set this value to false, preventing any further clicks.
I don't have this exact requirement, I just needed an always read only checkbox, and it seems to solve the problem nicely. Also note Goran's comment below about the Focusable property.
This answer is not your question, but it answers the question from the title.
Checkbox in WPF does not have the IsReadOnly property.
But, similar behavior is achieved using properties
IsHitTestVisible="False" and Focusable="False"
<CheckBox IsHitTestVisible="False"
Focusable="False"/>
I don't think that creating a whole control for this is necessary.
The issue that you're running into comes from the fact that the place where you see 'the check' isn't really the checkbox, it's a bullet. If we look at the ControlTemplate for a CheckBox we can see how that happens (Though I like the Blend template better). As a part of that, even though your binding on the IsChecked property is set to OneWay it is still being updated in the UI, even if it is not setting the binding value.
As such, a really simple way to fix this, is to just modify the ControlTemplate for the checkbox in question.
If we use Blend to grab the control template we can see the Bullet inside the ControlTemplate that represents the actual checkbox area.
<BulletDecorator SnapsToDevicePixels="true"
Background="Transparent">
<BulletDecorator.Bullet>
<Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
IsChecked="{TemplateBinding IsChecked}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderPressed="{TemplateBinding IsPressed}" />
</BulletDecorator.Bullet>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</BulletDecorator>
In here, the IsChecked and RenderPressed are what are actually making the 'Check' appear, so to fix it, we can remove the binding from the IsChecked property on the ComboBox and use it to replace the TemplateBinding on the IsChecked property of the Bullet.
Here's a small sample demonstrating the desired effect, do note that to maintain the Vista CheckBox look the PresentationFramework.Aero dll needs to be added to the project.
<Window x:Class="Sample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
Title="Window1"
Height="300"
Width="300">
<Window.Resources>
<SolidColorBrush x:Key="CheckBoxFillNormal"
Color="#F4F4F4" />
<SolidColorBrush x:Key="CheckBoxStroke"
Color="#8E8F8F" />
<Style x:Key="EmptyCheckBoxFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle SnapsToDevicePixels="true"
Margin="1"
Stroke="Black"
StrokeDashArray="1 2"
StrokeThickness="1" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CheckRadioFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle SnapsToDevicePixels="true"
Margin="14,0,0,0"
Stroke="Black"
StrokeDashArray="1 2"
StrokeThickness="1" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CheckBoxStyle1"
TargetType="{x:Type CheckBox}">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="Background"
Value="{StaticResource CheckBoxFillNormal}" />
<Setter Property="BorderBrush"
Value="{StaticResource CheckBoxStroke}" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="FocusVisualStyle"
Value="{StaticResource EmptyCheckBoxFocusVisual}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator SnapsToDevicePixels="true"
Background="Transparent">
<BulletDecorator.Bullet>
<Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
RenderMouseOver="{TemplateBinding IsMouseOver}" />
</BulletDecorator.Bullet>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="HasContent"
Value="true">
<Setter Property="FocusVisualStyle"
Value="{StaticResource CheckRadioFocusVisual}" />
<Setter Property="Padding"
Value="4,0,0,0" />
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<CheckBox x:Name="uiComboBox"
Content="Does not set the backing property, but responds to it.">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator SnapsToDevicePixels="true"
Background="Transparent">
<BulletDecorator.Bullet>
<Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
IsChecked="{Binding MyBoolean}">
</Microsoft_Windows_Themes:BulletChrome>
</BulletDecorator.Bullet>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="HasContent"
Value="true">
<Setter Property="FocusVisualStyle"
Value="{StaticResource CheckRadioFocusVisual}" />
<Setter Property="Padding"
Value="4,0,0,0" />
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<TextBlock Text="{Binding MyBoolean, StringFormat=Backing property:{0}}" />
<CheckBox IsChecked="{Binding MyBoolean}"
Content="Sets the backing property." />
</StackPanel>
</Grid>
</Window>
And the code behind, with our backing Boolean value:
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
private bool myBoolean;
public bool MyBoolean
{
get
{
return this.myBoolean;
}
set
{
this.myBoolean = value;
this.NotifyPropertyChanged("MyBoolean");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
I had a need for the AutoCheck functionality be off as well for a Checkbox/RadioButton, where I wanted to handle the Click event without having the control auto-check. I've tried various solutions here and on other threads and was unhappy with the results.
So I dug into what WPF is doing (using Reflection), and I noticed:
Both CheckBox & RadioButton inherit from the ToggleButton control primitive. Neither of them have a OnClick function.
The ToggleButton inherits from the ButtonBase control primitive.
The ToggleButton overrides the OnClick function and does: this.OnToggle(); base.OnClick();
ButtonBase.OnClick does 'base.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, this));'
So basically, all I needed to do was override the OnClick event, don't call OnToggle, and do base.RaiseEvent
Here's the complete code (note that this can easily be reworked to do RadioButtons as well):
using System.Windows.Controls.Primitives;
public class AutoCheckBox : CheckBox
{
private bool _autoCheck = false;
public bool AutoCheck {
get { return _autoCheck; }
set { _autoCheck = value; }
}
protected override void OnClick()
{
if (_autoCheck) {
base.OnClick();
} else {
base.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, this));
}
}
}
I now have a CheckBox that doesn't auto-check, and still fires the Click event. Plus I can still subscribe to the Checked/Unchecked events and handle things there when I programmatically change the IsChecked property.
One final note: unlike other solutions that do something like IsChecked != IsChecked in a Click event, this won't cause the Checked/Unchecked/Indeterminate events to fire until you programmatically set the IsChecked property.
This is the class I've written to do something similar, for similar reasons (still raises all the Click and Command events as normal, but does not alter the binding source by default and does not auto-toggle. Unfortunately it does still have the animated fade-in-out on click, which is a bit strange if the click-handling code doesn't end up changing IsChecked.
public class OneWayCheckBox : CheckBox
{
private class CancelTwoWayMetadata : FrameworkPropertyMetadata
{
protected override void Merge(PropertyMetadata baseMetadata,
DependencyProperty dp)
{
base.Merge(baseMetadata, dp);
BindsTwoWayByDefault = false;
}
}
static OneWayCheckBox()
{
// Remove BindsTwoWayByDefault
IsCheckedProperty.OverrideMetadata(typeof(OneWayCheckBox),
new CancelTwoWayMetadata());
}
protected override void OnToggle()
{
// Do nothing.
}
}
Usage:
<yourns:OneWayCheckBox IsChecked="{Binding SomeValue}"
Command="{x:Static yourns:YourApp.YourCommand}"
Content="Click me!" />
(Note that the IsChecked binding is now one-way by default; you can declare it as TwoWay if you want, but that would defeat part of the point.)
Late answer, but I just came across the question looking for something else.
What you want is not a checkbox with unusual behaviour at all, what you want is a button with unusual appearance. It's always easier to change the appearance of a control than its behaviour.
Something along these lines ought to do (untested)
<Button Command="{Binding CommandThatStartsTask}">
<Button.Template>
<ControlTemplate>
<CheckBox IsChecked="{Binding PropertySetByTask, Mode=OneWay}" />
</ControlTemplate>
</Button.Template>
</Button>
Use Validation to block the boolean from getting toggled when you don't want it to - http://www.codeproject.com/KB/WPF/wpfvalidation.aspx
This is much less scary than the other answer, or hooking Clicked
I've been trying to create my generic ReadOnlyCheckBox style/template but I'm having a problem with the binding to the data. In the example you bind directly to the data from the ControlTemplate definition, but of course this is not really what I want, as I want to be able to declare the new checkbox something like this:
<CheckBox x:Name="uiComboBox" Content="Does not set the backing property, but responds to it."
Style="{StaticResource ReadOnlyCheckBoxStyle}" IsChecked="{Binding MyBoolean}" Click="uiComboBox_Click"/>
Except of course when I do this and then set the event trigger on the bullet to be a TemplateBinding of IsChecked I have exactly what I started with! I guess I don't understand why setting the binding directly in the bullet is different from setting IsChecked and then binding to that, isn't the TemplateBinding just a way of referencing what is set in the properties of the control being created? How is the Click triggering the UI update even tho the data does not get updated? Is there a trigger for Click I can override to stop the update?
I got all the DictionaryResource stuff working fine so I am happy with that, cheers for the pointer.
The other thing I was curious about was if it is possible to reduce my Control/Style template by using the BasedOn parameter in the style, then I would only override the things I actually need to change rather than declaring a lot of stuff that I think is part of the standard template anyway. I might have a play with this.
Cheers
ed
If it helps anyone, a fast and elegant solution I've found is to hook with the Checked and Unchecked events and manipulate the value based on your flag.
public bool readOnly = false;
private bool lastValidValue = false;
public MyConstructor()
{
InitializeComponent();
contentCheckBox.Checked += new
RoutedEventHandler(contentCheckBox_Checked);
contentCheckBox.Unchecked += new
RoutedEventHandler(contentCheckBox_Checked);
}
void contentCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (readOnly)
contentCheckBox.IsChecked = lastValidValue;
else
lastValidValue = (bool)contentCheckBox.IsChecked;
}
Wrap the CheckBox in a ContentControl. Make the ContentControl IsEnabled=False
Those two Properties are – IsHitTestVisible and Focusable
Make thse two properties to False. This makes the readonly checkbox in WPF.
So final XAML statement will be as follows for readonly checkbox in WPF –

WPF ControlTemplate for scrolling TreeView Control

I'm using a the TreeView control and it scrolls automatically to left-align TreeViewItem when one of them is clicked. I've gone looking at my Styles and ControlTemplates, but I haven't found anything. Is there a default ControlTemplate that causes this? I want to disable it.
The items scroll because the ScrollViewer calls BringIntoView() on them. So one way to avoid scrolling is to suppress the handling of the RequestBringIntoView event. You can try that out quickly by subclassing TreeView and instantiating this control instead:
public class NoScrollTreeView : TreeView
{
public class NoScrollTreeViewItem : TreeViewItem
{
public NoScrollTreeViewItem() : base()
{
this.RequestBringIntoView += delegate (object sender, RequestBringIntoViewEventArgs e) {
e.Handled = true;
};
}
protected override DependencyObject GetContainerForItemOverride()
{
return new NoScrollTreeViewItem();
}
}
protected override DependencyObject GetContainerForItemOverride()
{
return new NoScrollTreeViewItem();
}
}
after spending some hours on this problem i found a solution that works for me.
brians solution to prevent the RequestBringIntoView event on a TreeViewItem from bubbling was the first step. unfortunately this also stops a treeviewitem to be shown if you change the selected item programmatically by
yourtreeview.SelectedItem = yourtreeviewitem
so, for me the solution is to modify the controltemplate of the treeview as follows:
<Style x:Key="{x:Type TreeView}" TargetType="TreeView">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<Border Name="Border" BorderThickness="0" Padding="0" Margin="1">
<ScrollViewer Focusable="False" CanContentScroll="False" Padding="0">
<Components:AutoScrollPreventer Margin="0">
<ItemsPresenter/>
</Components:AutoScrollPreventer>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
the "autoscrollpreventer" is:
using System;
using System.Windows;
using System.Windows.Controls;
namespace LiveContext.Designer.GUI.Components {
public class AutoScrollPreventer : StackPanel
{
public AutoScrollPreventer() {
this.RequestBringIntoView += delegate(object sender, RequestBringIntoViewEventArgs e)
{
// stop this event from bubbling so that a scrollviewer doesn't try to BringIntoView..
e.Handled = true;
};
}
}
}
hope it helps..
It looks like I found a good clue on MSDN:
Sounds like this is an interaction
with the scrollviewer and the focus
system.
When an element is focused within a
ScrollViewer (which is part of the
TreeView template), the ScrollViewer
is instructed to make the element
visible. It automatically responds by
scrolling to the requested element.
The methods inside of ScrollViewer
that handle these focus requests are
all private and / or internal so you
really can't get to them. I don't
think there's too much you can do in
this case; it's just how focus works.
So, is that it? Surely there's a way to modify the TreeView template so that the ScrollViewer won't have this behavior...
Ok, I was finally able to get the default style like this:
using (Stream sw = File.Open(#"C:\TreeViewDefaults.xaml", FileMode.Truncate, FileAccess.Write))
{
Style ts = Application.Current.FindResource(typeof(TreeView)) as Style;
if (ts != null)
XamlWriter.Save(ts, sw);
}
Which produced:
<Style TargetType="TreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style.Triggers>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing">
<Setter Property="ItemsControl.ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate><VirtualizingStackPanel IsItemsHost="True" /></ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</Style.Triggers>
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="Panel.Background">
<Setter.Value><DynamicResource ResourceKey="{x:Static SystemColors.WindowBrushKey}" /></Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush">
<Setter.Value><SolidColorBrush>#FF828790</SolidColorBrush></Setter.Value>
</Setter>
<Setter Property="Border.BorderThickness">
<Setter.Value><Thickness>1,1,1,1</Thickness></Setter.Value>
</Setter>
<Setter Property="Control.Padding">
<Setter.Value><Thickness>1,1,1,1</Thickness></Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value><DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" /></Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility">
<Setter.Value><x:Static Member="ScrollBarVisibility.Auto" /></Setter.Value>
</Setter>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility">
<Setter.Value><x:Static Member="ScrollBarVisibility.Auto" /></Setter.Value>
</Setter>
<Setter Property="Control.VerticalContentAlignment">
<Setter.Value><x:Static Member="VerticalAlignment.Center" /></Setter.Value>
</Setter>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer CanContentScroll="False"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
Background="{TemplateBinding Panel.Background}"
Padding="{TemplateBinding Control.Padding}"
Name="_tv_scrollviewer_"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing">
<Setter Property="ScrollViewer.CanContentScroll" TargetName="_tv_scrollviewer_">
<Setter.Value><s:Boolean>True</s:Boolean></Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Which, unfortunately, doesn't look helpful. I don't see any properties in there for stopping the auto-scroll-focus thing.
Still looking...
Another fun tidbit: there is a overridable boolean value called HandlesScrolling that always returns true. After decompiling the source, it looks like this property is NEVER used (or it's being used in some deep, dark, secret place in XAML). I tried making my own TreeView control to set this value to false and it didn't work.

Categories

Resources