TwoWay binding doesn't update controls - wpf

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

Related

Update data binding by Enter Key in code behind WPF

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"
/>

WPF edit autogenerated column header text

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.

Convert DataGrid cell content

I have a DataGrid whose ItemsSource is set to a DataTable. The DataTable has a column of type DateTime, and I would like to display informational text (ie. "N/A") if the date in a particular cell is a certain value.
My first thought was to somehow bind the cell content to itself, and use a converter, but I can't seem to get it working correctly, and it seems as though there should be a better way.
Additionally, both the DataGrid and DataTable are dynamically generated, so this has to be done in the code behind.
Here's the code I tried initially:
// Create a new DataGridCellStyle
Style myStyle = new Style();
myStyle.TargetType = typeof(DataGridCell);
// Create the binding
Binding myBinding = new Binding();
myBinding.RelativeSource = RelativeSource.Self;
myBinding.Converter = new DateTimeToStringConverter();
// Add the Content setter
Setter mySetter = new Setter();
mySetter.Property = ContentProperty;
mySetter.Value = myBinding;
myStyle.Setters.Add(setter);
// Set the Style and ItemsSource
myDataGrid.CellStyle = myStyle ;
myDataGrid.ItemsSource = myDataTable.DefaultView;
DateTimeToStringConverter does implement IValueConverter, but I'm guessing the problem lies somewhere with the binding, since DateTimeToStringConverter is never actually called when the DataGrid is displayed.
At first, you Add the variable with the name setter to the Setters collection, but you are define the variable with the name mySetter. It may be a reason, why your Converter is not actually called.
Also the solution for your problem will be a bit more complicated.
Actually the Convert get a value of type RowDataView which contains a data for whole row. There is not an information in the converter about a Column or a Cell that is actually binded.
Better will be skip AutoGenerateColumns and generate them programmatically.
Here is example:
myDataGrid.ItemsSource = myDataTable.DefaultView;
myDataGrid.AutoGenerateColumns = false;
foreach (DataColumn column in myDataTable.Columns)
{
Binding binding = new Binding(column.ColumnName)
{
Converter = new DateTimeToStringConverter()
};
DataGridColumn gridColumn = new DataGridTextColumn
{
SortMemberPath = column.ColumnName,
Header = column.ColumnName,
Binding = binding
};
myDataGrid.Columns.Add(gridColumn);
}
Of course, for a performance will be better use the converter only in a DateTime columns.

Overriding DataGridTextColumn

I am trying to provide a DataGrid column that behaves like the DataGridTextColumn, but with an additional button in editing mode. I looked at DataGridTemplateColumn, but it appears easier to subclass the DataGridTextColumn as below
The problem is the textBox loses its binding when added to the grid. That is, changes to its Text property are not reflected in the non-editing TextBlock or the underlying view-mode
Any thoughts on why this might be and how I can work around it?
public class DataGridFileColumn : DataGridTextColumn
{
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
TextBox textBox = (TextBox)base.GenerateEditingElement(cell, dataItem);
Button button = new Button { Content = "..." };
Grid.SetColumn(button, 1);
return new Grid
{
ColumnDefinitions = {
new ColumnDefinition(),
new ColumnDefinition { Width = GridLength.Auto },
},
Children = {
textBox,
button,
},
};
}
}
I'm using .NET 3.5 and the WPF toolkit
It turns out you also need to override PrepareCellForEdit, CommitCellEdit and CancelCellEdit
The base class assumes (not unreasonably) that the FrameworkElement passed in will be a TextBox
I think you have to set up the binding manually in the GenerateEditingElement(...) method.
Once you've grabbed the TextBox from the base class, set up its binding like this:
textBox.DataContext = dataItem;
textBox.SetBinding(TextBlock.TextProperty, Binding);
This works for me anyway.
Note, I'm not sure why this works, as reading the documentation for GenerateEditingCell implies to me that the TextBox that you grab from the base class should already have its bindings set up properly. However, the above approach is what they did in this blog post.
EDIT:
You don't actually need to set up the binding, it is done already (as it says in the docs). You do need to set up the DataContext though, as for some reason this isn't set up on the textBox returned from the base class.

WPF: Data binding with code

How do I use data-binding from code (C# or VB)?
This is what I have so far, but it is displaying Binding.ToString instead of m_Rep.FirstName.
Public ReadOnly Property TabCaption As Object
Get
Return New Label With {.Foreground = Brushes.Black, .Content = New Binding("FirstName"), .DataContext = m_Rep}
End Get
End Property
Yes, binding in code is a little different from straight assignment (which is how XAML makes it look like it works).
I can give you an example in C# - shouldn't be too far removed from VB.NET.
var label = new Label { Foreground = Brushes.Black, DataContext = m_Rep };
label.SetBinding(Label.ContentProperty, new Binding("FirstName"));
return label;
So the "SetBinding" method binds the "FirstName" path (of the DataContext) to the label's Content property.
You should use m_Rep as a Source of Binding
I have some sample C# code for you as below
Person myDataSource = new Person("Joe");
// Name is a property which you want to bind
Binding myBinding = new Binding("Name");
myBinding.Source = myDataSource;
// myText is an instance of TextBlock
myText.SetBinding(TextBlock.TextProperty, myBinding);
Hope to help

Resources