Wpf Decimals Styling - wpf

I want to Style a TextBox with decimal places like this:
How can I do that ?

You can extend the TextBox like this.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
public class DecimalTextBox : TextBox
{
public static readonly DependencyProperty FloatColorProperty = DependencyProperty.Register("FloatColor", typeof(Color), typeof(DecimalTextBox), new FrameworkPropertyMetadata(Colors.Red));
public Color FloatColor
{
get { return (Color)GetValue(FloatColorProperty); }
set { SetValue(FloatColorProperty, value); }
}
protected TextBlock _textBlock;
protected FrameworkElement _textBoxView;
public DecimalTextBox()
{
_textBlock = new TextBlock() { Margin = new Thickness(1, 0, 0, 0) };
Loaded += ExTextBox_Loaded;
}
private void ExTextBox_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= ExTextBox_Loaded;
// hide the original drawing visuals, by setting opacity on their parent
var visual = this.GetChildOfType<DrawingVisual>();
_textBoxView = (FrameworkElement)visual.Parent;
_textBoxView.Opacity = 0;
// add textblock to do the text drawing for us
var grid = this.GetChildOfType<Grid>();
if (grid.Children.Count >= 2)
grid.Children.Insert(1, _textBlock);
else
grid.Children.Add(_textBlock);
}
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnLostKeyboardFocus(e);
_textBoxView.Opacity = 0;
_textBlock.Visibility = Visibility.Visible;
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
_textBoxView.Opacity = 1;
_textBlock.Visibility = Visibility.Collapsed;
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
// making sure text on TextBlock is updated as per TextBox
var dotPos = Text.IndexOf('.');
var textPart1 = dotPos == -1 ? Text : Text.Substring(0, dotPos + 1);
var textPart2 = (dotPos == -1 || dotPos >= (Text.Length-1)) ? null : Text.Substring(dotPos + 1);
_textBlock.Inlines.Clear();
_textBlock.Inlines.Add(new Run {
Text = textPart1,
FontFamily = FontFamily,
FontSize = FontSize,
Foreground = Foreground });
if (textPart2 != null)
_textBlock.Inlines.Add(new Run {
Text = textPart2,
FontFamily = FontFamily,
TextDecorations = System.Windows.TextDecorations.Underline,
BaselineAlignment = BaselineAlignment.TextTop,
FontSize = FontSize * 5/6,
Foreground = new SolidColorBrush(FloatColor) });
}
}
public static class HelperExtensions
{
public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
}
XAML code usage
<local:DecimalTextBox FloatColor="Maroon" />
And your output should look like this:
Update 05/17
Explanation: As you can see from the image, the DecimalTextBox displays the text in formatted mode only when its not focused.
I had initially developed the control to support formatting during edit (which can still be done by commenting the methods OnLostKeyboardFocus, and OnGotKeyboardFocus) - but because of the font-size difference the cursor positioning was getting slightly skewed, which in turn would translate to bad user experience.
Therefore, implemented the swap logic during GotFocus and LostFocus to fix that.

You can't do that with a TextBox, because TextBox only accepts color changes to the entire text. You should try with RichTextBox, that allows loop throug TextRange's. Look at this sample of syntax highlighting with a RichTextBox.
I actually understood how it works and made it:
private void richTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
richTextBox.TextChanged -= this.richTextBox_TextChanged;
if (richTextBox.Document == null)
return;
TextRange documentRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
documentRange.ClearAllProperties();
int dotIndex = documentRange.Text.IndexOf(".");
if(dotIndex == -1)
{
richTextBox.TextChanged += this.richTextBox_TextChanged;
return;
}
TextPointer dotStart = GetPoint(richTextBox.Document.ContentStart, dotIndex);
TextPointer dotEnd = dotStart.GetPositionAtOffset(1, LogicalDirection.Forward);
TextRange initRange = new TextRange(richTextBox.Document.ContentStart, dotStart);
TextRange endRange = new TextRange(dotEnd, richTextBox.Document.ContentEnd);
endRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
richTextBox.TextChanged += this.richTextBox_TextChanged;
}
Suscribe the textbox TextChanged event to this method. You can now set the styles you want to every part of the text like this:
To change the last part (after the dot char) endRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
To change the first part (before the dot char) is the same but for the initRange variable. If you want to change the 'dot' style, then create a new TextRange with dotStart and dotEnd TextPointers and apply styles to it. You can do other things like change font style, size, etc.
This code result looks like this:
All this is just for style. For checking that is a number is up to you.

I would define a custom control with this main properties:
FloatNumber: the original number, that should be a DependencyProperty to be Bind from the control.
NumberOfDecimalDigits: a number to choose how many decimal digits to represent, that should be a DependencyProperty to be Bind from the control.
FirstPart: a string that will contain the first part of the decimal number
Decimals: a string that will contain the decimal digits of FloatNumber
Of course this is just a scratch, those properties could be implemented better to extract FloatNumber parts.
public partial class DecimalDisplayControl : UserControl, INotifyPropertyChanged
{
public DecimalDisplayControl()
{
InitializeComponent();
(Content as FrameworkElement).DataContext = this;
}
public static readonly DependencyProperty NumberOfDecimalDigitsProperty =
DependencyProperty.Register(
"NumberOfDecimalDigits", typeof(string),
typeof(DecimalDisplayControl), new PropertyMetadata(default(string), OnFloatNumberChanged));
public static readonly DependencyProperty FloatNumberProperty =
DependencyProperty.Register(
"FloatNumber", typeof(string),
typeof(DecimalDisplayControl), new PropertyMetadata(default(string), OnFloatNumberChanged));
private static void OnFloatNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as DecimalDisplayControl).OnFloatNumberChanged();
}
protected void OnFloatNumberChanged()
{
int numberOfDecimalDigits = Convert.ToInt32(NumberOfDecimalDigits);
float fullNumber = Convert.ToSingle(FloatNumber);
float firstPart = (float)Math.Truncate(fullNumber);
float fullDecimalPart = fullNumber - firstPart;
int desideredDecimalPart = (int)(fullDecimalPart * Math.Pow(10, numberOfDecimalDigits));
FirstPart = $"{firstPart}.";
Decimals = desideredDecimalPart.ToString();
}
public string FloatNumber
{
get => (string)GetValue(FloatNumberProperty);
set { SetValue(FloatNumberProperty, value); }
}
public string NumberOfDecimalDigits
{
get => (string)GetValue(NumberOfDecimalDigitsProperty);
set { SetValue(NumberOfDecimalDigitsProperty, value); }
}
private string _firstPart;
public string FirstPart
{
get => _firstPart;
set
{
if (_firstPart == value)
return;
_firstPart = value;
OnPropertyChanged();
}
}
private string _decimals;
public string Decimals
{
get => _decimals;
set
{
if (_decimals == value)
return;
_decimals = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Its XAML:
<UserControl
x:Class="WpfApp1.CustomControls.DecimalDisplayControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
FontSize="20"
Foreground="Black"
Text="{Binding FirstPart}" />
<TextBlock
FontSize="10"
Foreground="Red"
Text="{Binding Decimals}"
TextDecorations="Underline" />
</StackPanel>
</UserControl>
Then you can use it in your page and bind a property to make it change dynamically:
<Grid>
<StackPanel VerticalAlignment="Center" Orientation="Vertical">
<customControls:DecimalDisplayControl
HorizontalAlignment="Center"
VerticalAlignment="Center"
NumberOfDecimalDigits="2"
FloatNumber="{Binding MyNumber}" />
<TextBox
Width="200"
VerticalAlignment="Center"
Text="{Binding MyNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
The final result:

Related

How to show text as background in TextBox correctly?

i have a TextBox and a text hint that show as background:
but location of text as background which is not part of the Text of the base TextBox is not correctly.
xaml:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:v="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="152,19,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"
v:Autocomplete.Hint ="abcd"/>
</Grid>
Autocomplete.cs:
namespace WpfApplication2
{
public static class Autocomplete
{
#region Hint
public static string GetHint(DependencyObject obj)
{
return (string)obj.GetValue(HintProperty);
}
public static void SetHint(DependencyObject obj, string value)
{
obj.SetValue(HintProperty, value);
}
public static readonly DependencyProperty HintProperty =
DependencyProperty.RegisterAttached("Hint", typeof(string), typeof(Autocomplete), new PropertyMetadata(string.Empty, OnTextBoxBaseFocus));
private static string hintText = string.Empty;
private static void OnTextBoxBaseFocus(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBoxBase txtBase = (TextBoxBase)d;
hintText = GetHint(d);
if (txtBase == null)
return;
if ((string)e.NewValue != null && !GetHint(d).Contains(" "))
{
txtBase.GotFocus += txtBase_GotFocus;
txtBase.LostFocus += txtBase_LostFocus;
}
else
txtBase.TextChanged -= OnChanged;
}
static void txtBase_GotFocus(object sender, RoutedEventArgs e)
{
AutocompleteText(sender);
}
static void txtBase_LostFocus(object sender, RoutedEventArgs e)
{
TextBoxBase txtBase = (TextBoxBase)sender;
// Hide Autocomplete hint
txtBase.Background = null;
}
private static void OnChanged(object sender, TextChangedEventArgs e)
{
AutocompleteText(sender);
}
private static void AutocompleteText(object sender)
{
TextBoxBase txtBase = (TextBoxBase)sender;
if (txtBase != null && txtBase.Focus())
{
// Show Autocomplete hint
var visual = new TextBlock()
{
FontStyle = FontStyles.Normal,
Text = hintText,
Foreground = Brushes.Gray
};
txtBase.Background = new VisualBrush(visual)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Center,
Transform = new TranslateTransform(3, 0)
};
}
else
{
// Hide Autocomplete hint
txtBase.Background = null;
}
}
#endregion
}
}
i expected:
How to show Autocomplete.Hint as expected?.Thanks for help me !
One way around this is to use a TextBox as your visual instead of TextBlock. This TextBox must have the same BorderThickness and the same Size as the original TextBoxBase. Therefore your AutocompleteText method should change like this:
private static void AutocompleteText(object sender)
{
TextBoxBase txtBase = (TextBoxBase)sender;
if (txtBase != null && txtBase.Focus())
{
// Show Autocomplete hint
var visual = new TextBox()
{
BorderThickness = txtBase.BorderThickness,
BorderBrush = Brushes.Transparent,
Width = txtBase.ActualWidth,
Height = txtBase.ActualHeight,
Text = hintText,
Foreground = Brushes.Gray
};
txtBase.Background = new VisualBrush(visual)
{
Stretch = Stretch.None,
};
}
else
{
// Hide Autocomplete hint
txtBase.Background = null;
}
}

WPF: how to implement a button that make 2 other buttons visible with fading

I want to Implement special button and i don't know even how to start with this.
I want my Button's content property to be: Play. When clicking on it, I want 2 other Buttons to pop up in the left and in the right sides: Single Play and Parallel Play
All you have to do is to create your 3 buttons and then put a visibility converter on your 2 sides buttons. Create a property that will hold if they should be visible or not and bind the visibility converter to this property. The Play button should modify this property when clicked.
I hope this gives you an idea on how to start with this.
After a lot of discussion, here is the result to solve this problem:
xaml:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Horizontal">
<Button Name="btnSinglePlay" Visibility="Collapsed" my:VisibilityAnimation.IsActive="True">SinglePlay</Button>
<Button Name="btnPlay" Click="btnPlay_Click">Play</Button>
<Button Name="btnParallelPlay" Visibility="Collapsed" my:VisibilityAnimation.IsActive="True">ParallelPlay</Button>
</StackPanel>
</Grid>
C# to set the 2 sides button visible.
private void btnPlay_Click(object sender, RoutedEventArgs e)
{
btnSinglePlay.Visibility = Visibility.Visible;
btnParallelPlay.Visibility = Visibility.Visible;
}
And the c# code to permit the fade in/fade out. It comes from WPF Fade Animation so props to Anvaka, not to me.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Animation;
namespace WpfApplication3
{
public class VisibilityAnimation : DependencyObject
{
private const int DURATION_MS = 200;
private static readonly Hashtable _hookedElements = new Hashtable();
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.RegisterAttached("IsActive",
typeof(bool),
typeof(VisibilityAnimation),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsActivePropertyChanged)));
public static bool GetIsActive(UIElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool)element.GetValue(IsActiveProperty);
}
public static void SetIsActive(UIElement element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsActiveProperty, value);
}
static VisibilityAnimation()
{
UIElement.VisibilityProperty.AddOwner(typeof(FrameworkElement),
new FrameworkPropertyMetadata(Visibility.Visible, new PropertyChangedCallback(VisibilityChanged), CoerceVisibility));
}
private static void VisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// So what? Ignore.
}
private static void OnIsActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var fe = d as FrameworkElement;
if (fe == null)
{
return;
}
if (GetIsActive(fe))
{
HookVisibilityChanges(fe);
}
else
{
UnHookVisibilityChanges(fe);
}
}
private static void UnHookVisibilityChanges(FrameworkElement fe)
{
if (_hookedElements.Contains(fe))
{
_hookedElements.Remove(fe);
}
}
private static void HookVisibilityChanges(FrameworkElement fe)
{
_hookedElements.Add(fe, false);
}
private static object CoerceVisibility(DependencyObject d, object baseValue)
{
var fe = d as FrameworkElement;
if (fe == null)
{
return baseValue;
}
if (CheckAndUpdateAnimationStartedFlag(fe))
{
return baseValue;
}
// If we get here, it means we have to start fade in or fade out
// animation. In any case return value of this method will be
// Visibility.Visible.
var visibility = (Visibility)baseValue;
var da = new DoubleAnimation
{
Duration = new Duration(TimeSpan.FromMilliseconds(DURATION_MS))
};
da.Completed += (o, e) =>
{
// This will trigger value coercion again
// but CheckAndUpdateAnimationStartedFlag() function will reture true
// this time, and animation will not be triggered.
fe.Visibility = visibility;
// NB: Small problem here. This may and probably will brake
// binding to visibility property.
};
if (visibility == Visibility.Collapsed || visibility == Visibility.Hidden)
{
da.From = 1.0;
da.To = 0.0;
}
else
{
da.From = 0.0;
da.To = 1.0;
}
fe.BeginAnimation(UIElement.OpacityProperty, da);
return Visibility.Visible;
}
private static bool CheckAndUpdateAnimationStartedFlag(FrameworkElement fe)
{
var hookedElement = _hookedElements.Contains(fe);
if (!hookedElement)
{
return true; // don't need to animate unhooked elements.
}
var animationStarted = (bool)_hookedElements[fe];
_hookedElements[fe] = !animationStarted;
return animationStarted;
}
}
}

Highlight text in Datagrid

I have an implementation of highlight text in datagrid when the user input a text in searchbox and click on search. The problem is when the user clicks the scrollbar in datagrid, the hightlight is gone. Below is my custom class for hightlighting:
public class SearchableTextBlock
{
public static DependencyProperty SearchPhraseProperty =
DependencyProperty.RegisterAttached(
"SearchPhrase",
typeof(string),
typeof(SearchableTextBlock), new PropertyMetadata("", SearchPhraseChanged));
public static string GetSearchPhrase(UIElement element)
{
return (string)element.GetValue(SearchPhraseProperty);
}
public static void SetSearchPhrase(UIElement element, string value)
{
element.SetValue(SearchPhraseProperty, value);
}
public static void SearchPhraseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null)
return;
if ((d as TextBlock) != null)
{
TextBlock tbx = d as TextBlock;
String text = tbx.Text;
tbx.Inlines.Clear();
string txtStore = "";
//Loops throught the entire text
for (int i = 0; i < text.Length; i++)
{
txtStore += text[i];
//If search phrase is found
if (txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper()) > -1)
{
//Creates the formatting for regular text
Run runRegular = new Run();
runRegular.Text = txtStore.Substring(0, txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper()));
//Creates the formatting for the found text
//Foreground is hardcoded to red.
Run runHighlight = new Run();
runHighlight.Text = txtStore.Substring(txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper()), txtStore.Length - (txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper())));
runHighlight.Foreground = new SolidColorBrush(Colors.Red);
runHighlight.FontWeight = FontWeights.Bold;
//Inserts the formatted text to the textblock
txtStore = "";
tbx.Inlines.Add(runRegular);
tbx.Inlines.Add(runHighlight);
}
}
Run runRemaining = new Run();
runRemaining.Text = txtStore;
tbx.Inlines.Add(runRemaining);
}
}
}
Here's my XAML:
<sdk:DataGridTemplateColumn x:Name="Database" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Database}"
sTextBlock:SearchableTextBlock.SearchPhrase="{Binding SDatabase, Mode=TwoWay}"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
Thanks!
You could try disable the DataGrid's virtualization. Try Xusan's solution in this post.
Hope this helps.
Miguel

WP7 - Animating add/remove item in a ListBox

I know you can achieve this in Silverlight 4 by playing with the ListBoxItem style's LayoutStates, i.e. BeforeUnloaded, BeforeLoaded and AfterLoaded.
It doesn't seem to be working at all in WP7 although these states exist in the default style.
I am currently using version 7.1.
Is there any way I can get this working?
Thanks,
Xin
for this I used Artefact Animator, it's for Silverlight but works perfectly for WP7 also. The code shows only the addition. Whole code from the project's sample page.
MainPage.xaml
<UserControl.Resources>
<!-- ADDS SMOOTH SCROLL -->
<ItemsPanelTemplate x:Key="ItemsPanelTemplate">
<StackPanel/>
</ItemsPanelTemplate>
</UserControl.Resources>
<Grid>
<ListBox x:Name="lb" Height="247" Width="100" ItemsPanel="{StaticResource ItemsPanelTemplate}" />
<Button x:Name="addBtn" Content="Add" Height="72" HorizontalAlignment="Left" Margin="159,145,0,0" VerticalAlignment="Top" Width="160" />
</Grid>
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage
{
private static ScrollViewer _scrollViewer;
// Constructor
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
// INIT
lb.Items.Clear();
lb.UpdateLayout();
// SCROLL INTERACTION
_scrollViewer = FindVisualChild<ScrollViewer>(lb);
var bar = FindVisualChild<ScrollBar>(_scrollViewer);
if (bar != null)
bar.ValueChanged += (s, args) => SetValue(ListBoxScrollOffsetProperty, args.NewValue);
// INPUT
addBtn.Click += (s, args) => AddItem();
}
private void AddItem()
{
// Create New ListBoxItem
var lbi = new ListBoxItem
{
Content = "Item " + lb.Items.Count,
RenderTransform = new CompositeTransform
{
TranslateX = -lb.Width
},
};
// Add ListBoxItem
lb.Items.Add(lbi);
lb.UpdateLayout();
// Animate In Item
ArtefactAnimator.AddEase(lbi.RenderTransform, CompositeTransform.TranslateXProperty, 0, 1, AnimationTransitions.CubicEaseOut, 0);
ArtefactAnimator.AddEase(this, ListBoxScrollOffsetProperty, _scrollViewer.ScrollableHeight, .8, AnimationTransitions.CubicEaseOut, 0);
}
// LISTBOX SCROLL OFFSET
public static readonly DependencyProperty ListBoxScrollOffsetProperty =
DependencyProperty.Register("ListBoxScrollOffset", typeof(double), typeof(MainPage), new PropertyMetadata(0.0, OnListBoxScrollOffsetChanged));
private static void OnListBoxScrollOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
_scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
}
public double ListBoxScrollOffset
{
get
{
return (double)GetValue(ListBoxScrollOffsetProperty);
}
set
{
SetValue(ListBoxScrollOffsetProperty, value);
}
}
// VISUAL HELPER
public static childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
{
return (childItem)child;
}
else
{
var childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
{
return childOfChild;
}
}
}
return null;
}
}

Silverlight - binding to control borderthickness

I'm trying to better understand Silverlights binding mechanism and so have created a simple program that will change the borderthickness of a listbox on the press of a button. However it doesn't work and I can't figure out what I am doing wrong. Any ideas?
XAML:
<Grid x:Name="LayoutRoot" Background="White">
<ListBox Height="100" HorizontalAlignment="Left" Margin="134,102,0,0" Name="listBox1" VerticalAlignment="Top" Width="120" BorderThickness="{Binding TheThickness, Mode=TwoWay}" />
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="276,36,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
Code:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication4
{
public partial class MainPage : UserControl
{
private TestClass testInst = new TestClass();
public MainPage()
{
InitializeComponent();
listBox1.DataContext = testInst;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
testInst.TheThickness = 10;
}
}
public class TestClass
{
private int theThickness = 5;
public int TheThickness
{
get { return theThickness; }
set
{
theThickness = value;
NotifyPropertyChanged("TheThickness");
}
}
public event PropertyChangedEventHandler PropertyChanged;
// NotifyPropertyChanged will raise the PropertyChanged event, passing the source property that is being updated.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
A border thickness is of Type Thickness which has multiple values for Top, Bottom, Left and Right. The XAML parser knows how to handle something like BorderThickness="5" correctly but in code you need to use the Thickness type. For example:-
public Thickness SelectedThickness
{
get { return (Thickness)GetValue(SelectedThicknessProperty); }
set { SetValue(SelectedThicknessProperty, value); }
}
public static readonly DependencyProperty SelectedThicknessProperty =
DependencyProperty.Register("SelectedThickness", typeof(Thickness), typeof(MyRectangle),
new PropertyMetadata(new Thickness() { Top = 1, Bottom = 1, Left = 1, Right = 1 }));
}
In this case the default Thickness of 1.
Edit Code more like yours:-
private Thickness theThickness = new Thickness() {Left = 5, Right = 5, Top = 5, Bottom = 5};
public Thickness TheThickness
{
get { return theThickness; }
set
{
theThickness = value;
NotifyPropertyChanged("TheThickness");
}
}

Resources