I have a FrameworkElementFactory works like a textbox created in the code, so there is no xaml code, and also I set this textbox with data binding in code. Now I want to update this textbox databinding by Enter key pressed. I have read one way for attached behavior in this Link, but it seems working with xaml code. Is there any way to set attached behavior in code behind?
ListBox DDF_List = new ListBox();
FrameworkElementFactory Editable_TextBox = new FrameworkElementFactory(typeof(TextBox));
Binding text_binding = new Binding("Value");
Editable_TextBox.SetBinding(TextBox.TextProperty, text_binding);
DataTemplate Text_Layout = new DataTemplate();
Text_Layout.VisualTree = Editable_TextBox;
DDF_List.ItemTemplate = Text_Layout;
You should almost certainly be doing this with a DataTemplate in XAML. What you've got is a prefect case for doing everything in XAML. But if you're committed to doing it the hard way, here's how.
With your FrameworkElementFactory, you can set it like any other dependency property on a FrameworkElementFactory:
Editable_TextBox.SetValue(
InputBindingsManager.UpdatePropertySourceWhenEnterPressedProperty,
TextBox.TextProperty);
More generally, here's now to apply that attached property to a TextBox in C#, where itemNameTextBox is the TextBox:
InputBindingsManager.SetUpdatePropertySourceWhenEnterPressed(itemNameTextBox,
TextBox.TextProperty);
With attached properties, this C#:
var itemNameTextBox = new TextBox { Name = "itemNameTextBox" };
var binding = new Binding("ItemName")
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
itemNameTextBox.SetBinding(TextBox.TextProperty, binding);
// This is the line you're asking for:
InputBindingsManager.SetUpdatePropertySourceWhenEnterPressed(itemNameTextBox,
TextBox.TextProperty);
Is an exact equivalent of this XAML:
<TextBox
Name="itemNameTextBox"
Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}"
b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"
/>
Related
The simplest example I could think of was the following:
TextBox tb1 = new TextBox();
TextBox tb2 = new TextBox();
this.Content = new StackPanel() { Children = { tb1, tb2 } };
Binding binding = new Binding("Text") {
Mode = BindingMode.TwoWay,
Source = tb1,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
tb2.SetBinding(TextBlock.TextProperty, binding);
When I start my application I expect the textboxes to update their text as soon as the other textbox's text changes. But neither the source textbox nor the target textbox updates its text when changing the other textbox. Is there a reason for this strange behavior and might there be a workaround?
(For specific reasons I cannot use XAML, where bindings always worked for me)
Update: When changing the text of one of the textboxes for the first time, the output window says The thread 0x#### has exited with code 259 (0x103).
You're using the wrong DependencyProperty.
tb2.SetBinding(**TextBlock**.TextProperty, binding);
Copied code works as expected when using TextBox.TextProperty
I have my own usercontrol named FlashControl in the mainwindow. I set the DataContext by following code in the mainwondow
(FlashControl.Content as FrameworkElement).DataContext = null;
(FlashControl.Content as FrameworkElement).DataContext = this.DataContext;
FlashControl.DataContext = this.DataContext;
My problem is whenever my datacontext change I need to call the above code to reset usercontrol's datacontext. Why Usercontrol's DataContext not updated automatically when main DataContext change? How to do automatic update? Am I missing something?
If you want automatic update dont set DataContext directly but Bind it to the value you want.
You should bind in xaml but if you want to do in code behind then you can do:
Binding myBinding = new Binding("DataContext");
myBinding.Source = this;
BindingOperations.SetBinding(FlashControl, FrameworkElement.DataContextProperty, myBinding);
I'm using a WPF DataGrid to display DataTable's.
I need to be able to edit this bound DataTables (Two-Way Binding).
I'm using the DataGrid as followed:
<DataGrid SelectionUnit="CellOrRowHeader" IsReadOnly="False" AutoGenerateColumns="True" ItemsSource="{Binding Path=SelectedItem.BindableContent, FallbackValue={x:Null}}" />
The Problem I have, the user can't edit the ColumnHeader's like cell content or rows.
The Screenshot below illustrates that porblem. The only thing I can do is sort the columns.
Is there a way to edit the column headers too, for example when the user clicks twice, or presses F2.
Maybe some Style' or a HeaderTemplate will do the job? I have already tried some styles and control templates I've found around the internet, but without any success.
EDIT:
I managed to display the column headers in a TextBox (and not in a TextBlock) within the AutogeneratingTextcolumn event handler:
private void _editor_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) {
// First: create and add the data template to the parent control
DataTemplate dt = new DataTemplate(typeof(TextBox));
e.Column.HeaderTemplate = dt;
// Second: create and add the text box to the data template
FrameworkElementFactory txtElement =
new FrameworkElementFactory(typeof(TextBox));
dt.VisualTree = txtElement;
// Create binding
Binding bind = new Binding();
bind.Path = new PropertyPath("Text");
bind.Mode = BindingMode.TwoWay;
// Third: set the binding in the text box
txtElement.SetBinding(TextBox.TextProperty, bind);
txtElement.SetValue(TextBox.TextProperty, e.Column.Header);
}
But I couldn't manage to set the binding correctly, if i edit the Text in the TextBoxes, it does not change the text in the Column.Header-Property (which is auto-generated by a binding to a DataTable like explained above).
You forgot to set the source of your binding and you mustn't set the value after the registration of the binding. The correct code would be the following:
private void asdf_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
DataTemplate dt = new DataTemplate(typeof(TextBox));
e.Column.HeaderTemplate = dt;
FrameworkElementFactory txtElement =
new FrameworkElementFactory(typeof(TextBox));
dt.VisualTree = txtElement;
Binding bind = new Binding();
bind.Path = new PropertyPath("Header");
bind.Mode = BindingMode.TwoWay;
// set source here
bind.Source = e.Column;
txtElement.SetBinding(TextBox.TextProperty, bind);
// You mustn't set the value here, otherwise the binding doesn't work
// txtElement.SetValue(TextBox.TextProperty, e.Column.Header);
}
Additionally you must change the binding property to Header, because you are adding the binding to the text property of the TextBox.
I'm trying to databind a combobox in WPF for the first time and I can't get it to happen.
The image below shows my code, can you please tell me what I am missing? I only want graphic stuff in the xaml.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Patient p = new Patient();
this.cbPatient.DataContext = p.SelfListAll();
this.cbPatient.DisplayMemberPath = "Name";
this.cbPatient.SelectedValuePath = "PatientIDInternal";
}
...
Short explanation: Just make the following change to your XAML:
<ComboBox ItemsSource="{Binding Path=patientList}" />
Then, in your Window_Loaded event handler, just add
this.DataContext = this
Then make a new member called patientList of type ObservableCollection<Patient>.
Long explanation:
You don't have a binding set up. You need to create one through XAML like this:
<ComboBox ItemsSource="{Binding Path=patientList}" />
Then, the combobox will look for a member or property called "patientList" on the object that is set as its DataContext. I'd recommend using an ObservableCollection for patientList.
Alternatively, to create one in code, you can follow the examples here:
http://msdn.microsoft.com/en-us/library/ms752347.aspx#specifying_the_binding_source
Binding myBinding = new Binding("patientList");
myBinding.DataContext = someObject; //whatever object has 'patientList' as a member
mycombobox.SetBinding(ComboBox.ItemsSourceProperty, myBinding);
This will set a binding on the mycombobox ComboBox with a path of patientList and a DataContext of someObject. In other words, mycombobox will show the contents of someObject.patientList (which would ideally be some ObservableCollection, so that updates to the collection notify the binding to update).
You need to actually add the binding, e.g.:
Binding binding = new Binding();
binding.Source = MySourceObject;
binding.Path = new PropertyPath("MyPropertyPath");
binding.Mode = BindingMode.OneWay;
BindingOperations.SetBinding(cbPatient, SomeDependencyProperty, binding);
Ok, here is the answer to how to populate a combobox in WPF. First, thanks to everyone above who made suggestions. The part I was missing was that I was not populating the ItemsSource property but the DataContext property. Again, thanks to everyone for their help.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Patient p = new Patient();
this.cbPatient.ItemsSource = p.SelfListAll();
this.cbPatient.DisplayMemberPath = "Name";
this.cbPatient.SelectedValuePath = "PatientIDInternal";
this.cbPatient.SelectedIndex = 0;
}
You need to set the ItemsSource property relative to the DataContext:
cbPatient.SetBinding(ItemsSourceProperty, new Binding());
EDIT
The ItemsSource property of the ComboBox is the property that should point to the collection of items to be shown.
The collection you are interested in, is in the DataContext.
The Binding is an object that keeps track of changes of the collection and reports them to the ComboBox and its Path is relative to the object in the DataContext.
Because the Binding also needs to know the ComboBox you use the static SetBinding method that ties the connection between ComboBox and the Binding.
As in your code the collection itself is in the DataContext, the Path is empty.
The ItemsSource property should point to the collection of Patients. Because the collection of Patients is already in the DataContext, the Binding's Path property is empty.
Suppose an class named Hospital has two properties: Patients and Docters (and perhaps more: Rooms, Appointments, ...) and you set the DataContext of the ComboBox to an instance of Hospital. Then you would have to set the Binding's Path Property to "Patients"
Now the ComboBox will display each item (Patient) in the collection. To specify how a single Patient should be displayed you need to set the ItemTemplate property of the ComboBox.
I'm trying to figure out if its possible to update an IValueConverter through the code behind.
My situation is that I've got two ComboBoxes. Once the first one is updated, I change the ItemsSource property of the second to be one of a variety of enums. I've grabbed an EnumToFriendlyNameConverter from CodeProject, but I'm not sure how to set it.
If I set the converter in the ItemsSource (see below) then it gets ignored when I next set the items source.
ItemsSource="{Binding Converter={StaticResource enumItemsConverter}}"
I found that it is possible by using an ItemTemplate but then I have to manually place in a label, which then has a different style to my other combobox. Getting the styles right just seems like a lot of work...
When you change the ItemsSource you just have to apply the converter again or modify the ItemsSource instead of replacing it.
e.g. create a new binding:
private void ChangeItemsSouce(IEnumerable newItems)
{
Binding binding = new Binding();
binding.Source = newItems;
binding.Converter = new EnumToFriendlyNameConverter();
comboBox.SetBinding(ComboBox.ItemsSourceProperty, binding);
}
Or modify the existing binding:
private void ChangeItemsSouce(IEnumerable newItems)
{
var binding = comboBox.GetBindingExpression(ComboBox.ItemsSourceProperty);
binding.ParentBinding.Source = newItems;
}