My UserControl contains a TextBox and a Button. The TextBox's Text is correctly populated by a dependency property called X.
My Goal:
Change the value of X (e.g. Text of the TextBox) when I press the Button.
I have defined the UserControl as follows:
<StackPanel Orientation="Horizontal" >
<TextBox Name="Xbox" Text="{Binding Path=X}" Width="50"/>
<Button Content="Current" Click="InsertCurrentBtnClick" />
</StackPanel>
With codebehind:
public double X
{
get { return (double)GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public static readonly DependencyProperty XProperty =
DependencyProperty.Register("X", typeof(double), typeof(MyUserControl), new PropertyMetadata(0.0));
private void InsertCurrentBtnClick(object sender, RoutedEventArgs e)
{
X = 0.7;
//BindingOperations.GetBindingExpression(this, XProperty).UpdateTarget();
//BindingOperations.GetBindingExpression(Xbox, TextBox.TextProperty).UpdateTarget();
//BindingOperations.GetBindingExpression(Xbox, XProperty).UpdateTarget();
//Xbox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
//GetBindingExpression(XProperty).UpdateTarget();
}
I have tried several things - one at a time - (see below X=0.7;) to force the update to the TextBox Text but nothing has helped so far.
Thanks in advance.
I'd write it in this way:
public double X
{
get { return (double)GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public static readonly DependencyProperty XProperty =
DependencyProperty.Register("X", typeof(double), typeof(MainPage), new PropertyMetadata(new PropertyChangedCallback(Callback)));
public static void Callback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
(o as MainPage).Xbox.Text = e.NewValue.ToString();
}
private void InsertCurrentBtnClick(object sender, RoutedEventArgs e)
{
X = 0.7;
}
And the xaml code:
<StackPanel Orientation="Horizontal" >
<TextBox Name="Xbox" Width="50"/>
<Button Content="Current" Click="InsertCurrentBtnClick" />
</StackPanel>
You need to set the DataContext for you Control. As I see X defined in your control, you need to do this :
public MyUserControl()
{
InitializeComponent();
// add this line
this.DataContext = this;
}
Although, you can bind it as well, just change the xaml:
<UserControl x:Class="SilverlightApplication1.MainPage"
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"
mc:Ignorable="d"
Name="myWidnow"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Horizontal" >
<TextBox Name="Xbox" Width="50" Text="{Binding ElementName=myWidnow, Path=X}" />
<Button Content="Current" Click="InsertCurrentBtnClick" />
</StackPanel>
</Grid>
Notice that I've added the Name proeprty to the UserControl.
In this case, you don't have to change anything in the code behid.
Related
I have an ObservableCollection of DataPoint objects. That class has a Data property. I have a DataGrid. I have a custom UserControl called NumberBox, which is a wrapper for a TextBox but for numbers, with a Value property that is bind-able (or at least is intended to be).
I want the DataGrid to display my Data in a column NumberBox, so the value can be displayed and changed. I've used a DataGridTemplateColumn, bound the Value property to Data, set the ItemsSource to my ObservableCollection.
When the underlying Data is added or modified, the NumberBox updates just fine. However, when I input a value in the box, the Data doesn't update.
I've found answers suggesting to implement INotifyPropertyChanged. Firstly, not sure on what I should implement it. Secondly, I tried to implement it thusly on both my DataPoint and my NumberBox. I've found answers suggesting to add Mode=TwoWay, UpdateSourceTrigger=PropertyChange to my Value binding. I've tried both of these, separately, and together. Obviously, the problem remains.
Below is the bare minimum project I'm currently using to try to make this thing work. What am I missing?
MainWindow.xaml
<Window xmlns:BindingTest="clr-namespace:BindingTest" x:Class="BindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid Name="Container" AutoGenerateColumns="False" CanUserSortColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserReorderColumns="False" CanUserAddRows="False" CanUserDeleteRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Sample Text" Width="100" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<BindingTest:NumberBox Value="{Binding Data}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Name="BTN" Click="Button_Click" Height="30" VerticalAlignment="Bottom" Content="Check"/>
</Grid>
</Window>
MainWindow.cs
public partial class MainWindow : Window
{
private ObservableCollection<DataPoint> Liste { get; set; }
public MainWindow()
{
InitializeComponent();
Liste = new ObservableCollection<DataPoint>();
Container.ItemsSource = Liste;
DataPoint dp1 = new DataPoint(); dp1.Data = 1;
DataPoint dp2 = new DataPoint(); dp2.Data = 2;
Liste.Add(dp1);
Liste.Add(dp2);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
BTN.Content = Liste[0].Data;
}
}
DataPoint.cs
public class DataPoint
{
public double Data { get; set; }
}
NumberBox.xaml
<UserControl x:Class="BindingTest.NumberBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="28" d:DesignWidth="200">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Name="Container" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
</Grid>
</UserControl>
NumberBox.cs
public partial class NumberBox : UserControl
{
public event EventHandler ValueChanged;
public NumberBox()
{
InitializeComponent();
}
private double _value;
public double Value
{
get { return _value; }
set
{
_value = value;
Container.Text = value.ToString(CultureInfo.InvariantCulture);
if (ValueChanged != null) ValueChanged(this, new EventArgs());
}
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(double),
typeof(NumberBox),
new PropertyMetadata(OnValuePropertyChanged)
);
public static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
double? val = e.NewValue as double?;
(d as NumberBox).Value = val.Value;
}
}
What am I missing?
Quite a few things actually.
The CLR property of a dependency property should only get and set the value of the dependency property:
public partial class NumberBox : UserControl
{
public NumberBox()
{
InitializeComponent();
}
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(double),
typeof(NumberBox),
new PropertyMetadata(0.0)
);
private void Container_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
Value = double.Parse(Container.Text, CultureInfo.InvariantCulture);
}
}
The TextBox in the control should bind to the Value property:
<TextBox Name="Container" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center"
Text="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}}"
PreviewTextInput="Container_PreviewTextInput"/>
The mode of the binding between the Value and the Data property should be set to TwoWay and also, and this is because the input control is in the CellTemplate of the DataGrid, the UpdateSourceTrigger should be set to PropertyChanged:
<local:NumberBox x:Name="nb" Value="{Binding Data, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
mm8's answer pointed me in the right direction.
The two key missing elements were indeed:
to change the TextBox in NumberBox.xaml such as
<TextBox Name="Container"
Text="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center"
/>
and to change the binding in MainWindow.xaml such as
...
<DataTemplate>
<BindingTest:NumberBox
Value="{Binding Data, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
...
With these two modifications, both the Value and Data are being updated two-ways inside my DataGridTemplaceColumn.
Binding to the text however proved problematic. WPF apparently uses en-US culture no matter how your system is setup, which is really bad as this control deals with numbers. Using this trick solves that problem, and now the correct decimal separator is recognised. In my case, I've added it in a static constructor for the same effect so NumberBox can be used in other applications as is.
static NumberBox()
{
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
}
I've tested this in my test project, and then again tested the integration into my real project. As far as I can tell, it holds water, so I'll consider this question answered.
I have a XAML UserControl, a combination of a Label, a TextBox and a ComboBox.
In the textbox I type a double value, which must be adjusted with a factor determined by my choice in the ComboBox. Always !
(In fact a unit conversion operation: meters to kilometers, feet to centimeters, etc.)
That way, I will always have consistent SI units "inside" the program
The logical place to do that would be inside the UserControl's code-behind.
Therefor I define a Dep Prop InternalValue, which will contain the adjusted value of the textbox.
I need to be able to bind to that DP.
I tried to do something like the code below, but that won't fly: I get the indicated compile error in TextChanged.
How can I do what I want?
public string TBText
{
get { return (string)GetValue(TBTextProperty); }
set { SetValue(TBTextProperty, value); }
}
public static readonly DependencyProperty TBTextProperty =
DependencyProperty.Register("TBText", typeof(string), typeof(UCInputField), new PropertyMetadata( new PropertyChangedCallback(TextChanged)));
private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
InternalValue = Convert.ToDouble(e.NewValue) * factor; // error: an object reference is required.
}
public double InternalValue
{
get { return (double)GetValue(InternalValueProperty); }
set { SetValue(InternalValueProperty, value); }
}
public static DependencyProperty InternalValueProperty =
DependencyProperty.Register("InternalValue", typeof(double), typeof(UCInputField));
public DimPostfix CBSelectedItem
{
get { return (DimPostfix)GetValue(CBSelectedItemProperty); }
set { SetValue(CBSelectedItemProperty, value); }
}
public static readonly DependencyProperty CBSelectedItemProperty =
DependencyProperty.Register("CBSelectedItem", typeof(DimPostfix), typeof(UCInputField),new PropertyMetadata(new PropertyChangedCallback(UnitChanged)));
static double factor;
private static void UnitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
factor = (e.NewValue as DimPostfix).Factor;
}
And here is the UserControl:
<UserControl
x:Class="MyProgram.Views.UCInputField"
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"
d:DesignHeight="45"
d:DesignWidth="250"
mc:Ignorable="d">
<StackPanel
x:Name="LayoutRoot"
Orientation="Horizontal">
<Label
Content="{Binding LBContent}"
Style="{StaticResource LabelStyle1}" />
<TextBox
x:Name="TB"
HorizontalAlignment="Stretch"
Text="{Binding TBText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<ComboBox
x:Name="CBBox"
Width="70"
DisplayMemberPath="Name"
ItemsSource="{Binding CBUnit}"
SelectedItem="{Binding CBSelectedItem}"/>
</StackPanel>
</UserControl>
And the control will be used like this:
<ip:UCInputField
CBSelectedItem="{Binding .....}"
CBUnit="{Binding ....}"
LBContent="Length"
InternalValue="{Binding ...}"
TBText="{Binding Path=Ucl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
As you can see TextChangedis a static method. So it needs a reference to an instance of your User-Control if you want to change properties there.
One of the method parameters is of the type DependencyObjectwhich is the object that owns the dependency-property that has been changed and can be casted into your User-Control.
private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myControl = (UCInputField)d; //This is the reference that is needed
myControl.InternalValue = Convert.ToDouble(e.NewValue) * factor; //You can user factor since it is static
}
I want bind ObservableCollection my custom UserControl but when I want add new element and I almost done but when I want add new element to collection my app crash with no reason. I thought maybe it is variable inconsistency. But I came with nothig trying with object/String/string. Maybe I done something wrong at start?
Custom UserControl XAML
<UserControl x:Class="backtrackPrototype.checklistItem"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="80" d:DesignWidth="480">
<Grid x:Name="LayoutRoot">
<TextBlock
x:Name="label"
MaxHeight="407"
HorizontalAlignment="Left"
Margin="0,17,0,16"
VerticalAlignment="Center"
Text="{Binding Path=Title, ElementName=checklistItem}"/>
<CheckBox x:Name="checkbox" HorizontalAlignment="Right" VerticalAlignment="Center" Checked="checkbox_Checked" Unchecked="checkbox_Unchecked" />
</Grid>
</UserControl>
Custom UserControl
public partial class checklistItem : UserControl
{
public string Title
{
get { return (string)this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(checklistItem), new PropertyMetadata(0));
public checklistItem()
{
InitializeComponent();
}
public bool isChecked()
{
if ((bool)checkbox.IsChecked) return true;
return false;
}
private void checkbox_Checked(object sender, RoutedEventArgs e)
{
//title.Foreground = Application.Current.Resources["PhoneAccentColor"];
label.Foreground = (SolidColorBrush)Application.Current.Resources["PhoneAccentBrush"];
}
private void checkbox_Unchecked(object sender, RoutedEventArgs e)
{
label.Foreground = new SolidColorBrush(Colors.White);
}
}
XAML in main page
<ListBox Height="479" ItemsSource="{Binding}" x:Name="CheckList">
<ListBox.ItemTemplate>
<DataTemplate>
<local:checklistItem Title="{Binding Title}" Width="397"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox
CS in main page
public ObservableCollection ListItems = new ObservableCollection();
ListItem item = new ListItem("Nowe",false);
ListItems.Add(item);
CheckList.DataContext = ListItems;
And finally List
public class ListItem
{
public string Title { get; set; }
public bool Checked { get; set; }
public ListItem(string title, bool isChecked=false)
{
Title = title;
Checked = isChecked;
}
}
I need someone who will look at code with fresh mind. Thank you.
UPDATE:
What's more for accessing controls in my CustomControl I use first anwser in that question .
Also I update my UserControl XAML.
UPDATE V2
When I'm using <TextBox Title="{Binding Title}" Width="397"/> insted of local:checklistItem it work just fine.
UPDATE V3
OK turns out that I didn't add proper DataContext to my UserControl so now checklistItem constructor looks like this
public checklistItem() {
InitializeComponent();
this.DataContext = this;
}
And controls are adding correctly but now binding for Title is not working. Because when I hardcode some title it working, binding not. But the same binding is working for default textbox.
I think you need to set the itemsSource rather than the DataContext. Setting DataContext on a Listbox will NOT generate the templated items
take out
ItemsSource="{Binding}"
from the Xaml
and change
CheckList.DataContext = ListItems;
to
CheckList.ItemsSource = ListItems;
I think that perhaps your binding in the XAML is incorrect. Your element name in the binding is LayoutRoot which is the name of your grid not your UserControl.
It is probably trying to find a property on the Grid called Title which it does not have.
I have a user control that contains 2 DoubleUpDown, I have bound point to that controls
<DoubleUpDown x:Name="X" Grid.Column="1" Grid.Row="0" Value="{Binding Path=Value.X, Mode=TwoWay" />
<DoubleUpDown x:Name="Y" Grid.Column="1" Grid.Row="1" Value="{Binding Path=Value.Y, Mode=TwoWay}" />
controls get updated pretty well when I change Value from outside, but Value stays unchanged when I change controls data.
I bound Value to user control from code inside
Point2DEditorView editor = new Point2DEditorView();
Binding binding = new Binding("Value");
binding.Mode = BindingMode.TwoWay;
editor.SetBinding(Point2DEditorView.ValueProperty, binding);
and Point2DEditorView.Value also changed when I insert new coordinates into controls. But that does not affect bound Value.
Point is a value type data. Because of this when you bind it to control boxing and unboxing occurs. For more information see this. So, you may easy solve this problem by creating your own class (not struct!):
class MyPoint
{
public int X { set; get; }
public int Y { set; get; }
}
And then bind this objects to your control and you will see that all works as you expect.
Update
First of all your DoubleUpDown is'n in standart FCL and I think your problem in it. There is a simple example where all works as expect. I created a simple UpDown control for it:
Point class
public class Point2D : INotifyPropertyChanged
{
private double x;
private double y;
public double X
{
set
{
if (value.Equals(x)) return;
x = value;
OnPropertyChanged();
}
get { return x; }
}
public double Y
{
set
{
if (value.Equals(y)) return;
y = value;
OnPropertyChanged();
}
get { return y; }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
UpDown xaml
<UserControl x:Name="doubleUpDown" x:Class="PointBind.DoubleUpDown"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="105" Height="33">
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=doubleUpDown}">
<TextBox Margin="5,5,0,5" Width="50" Text="{Binding Value}" />
<Button x:Name="Up" x:FieldModifier="private" Margin="5,5,0,5" Content="˄" Width="20" Click="Up_Click" />
<Button x:Name="Down" x:FieldModifier="private" Margin="0,5,0,5" Content="˅" Width="20" Click="Down_Click" />
</StackPanel>
</UserControl>
UpDown .cs
public partial class DoubleUpDown : UserControl
{
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(DoubleUpDown), new PropertyMetadata(0.0));
public DoubleUpDown()
{
InitializeComponent();
DataContext = this;
}
private void Up_Click(object sender, RoutedEventArgs e)
{
Value++;
}
private void Down_Click(object sender, RoutedEventArgs e)
{
Value--;
}
}
Point2DEditorView xaml
<UserControl x:Name="point2DEditorView" x:Class="PointBind.Point2DEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:local="clr-namespace:PointBind"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<local:DoubleUpDown Value="{Binding Point.X, ElementName=point2DEditorView, Mode=TwoWay}"/>
<local:DoubleUpDown Value="{Binding Point.Y, ElementName=point2DEditorView, Mode=TwoWay}"/>
</StackPanel>
</UserControl>
UpDown .cs
public partial class Point2DEditorView : UserControl
{
public Point2D Point
{
get { return (Point2D)GetValue(PointProperty); }
set { SetValue(PointProperty, value); }
}
// Using a DependencyProperty as the backing store for Point. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PointProperty =
DependencyProperty.Register("Point", typeof (Point2D), typeof (Point2DEditorView),
new PropertyMetadata(new Point2D {X = 10, Y = 20}));
public Point2DEditorView()
{
InitializeComponent();
}
}
Test form xaml
<Window x:Class="PointBind.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PointBind"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:Point2DEditorView x:Name="pointEditor"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="39,121,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
</Window>
And test form .cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
pointEditor.Point = new Point2D{X = 300, Y = 400};
}
}
Hope this helps.
I can't seem to get my control to actually take the focus:
XAML:
<Button Command={Binding SetGridToVisibleCommand} />
<Grid Visibility="{Binding IsGridVisible, Converter={con:VisibilityBooleanConverter}}">
<TextBox Text={Binding MyText} IsVisibleChanged="TextBox_IsVisibleChanged" />
</Grid>
XAML.cs:
private void TextBox_IsVisibleChanged(Object sender, DependencyPropertyChangedEventArgs e)
{
UIElement element = sender as UIElement;
if (element != null)
{
Boolean success = element.Focus(); //Always returns false and doesn't take focus.
}
}
The ViewModel does it's job of setting the IsGridVisible to true, and the converter does it's job by converting that value to Visibility.Visible (I snooped it).
Not all UIElements can be focused by default, have you tried setting Focusable to true before trying Focus()?
We use this with in our application:
public static class Initial
{
public static void SetFocus(DependencyObject obj, bool value)
{
obj.SetValue(FocusProperty, value);
}
public static readonly DependencyProperty FocusProperty =
DependencyProperty.RegisterAttached(
"Focus", typeof(bool), typeof(Initial),
new UIPropertyMetadata(false, HandleFocusPropertyChanged));
private static void HandleFocusPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = (UIElement)d;
if ((bool)e.NewValue)
element.Focus(); // Ignore false values.
}
}
And the usage is:
<TextBox Text="{Binding FooProperty, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="1" HorizontalAlignment="Stretch"
Style="{StaticResource EditText}" ui:Initial.Focus="True"/>
The original idea came from SO, but couldn't find the answer.
100% free code behind :P
HTH
I couldn't reproduce your problem, its working fine with me, try the following code on a new project as a proof of concept and see if it works with you:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Content="Click" Click="Button_Click" />
<Grid>
<TextBox Name="NameTextBox" Text="ddd"
IsVisibleChanged="TextBox_IsVisibleChanged" />
</Grid>
</StackPanel>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
UIElement element = sender as UIElement;
if (element != null)
{
Boolean success = element.Focus(); //Always returns false and doesn't take focus.
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (NameTextBox.IsVisible)
NameTextBox.Visibility = Visibility.Collapsed;
else
NameTextBox.Visibility = Visibility.Visible;
}
}