WPF: Data binding with code - wpf

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

Related

Get WPF TabItem container from UserControl

I am setting the content of a UserControl, SIASystemTab, to a TabItem, ConfigTab. How do you access the TabItem from the UserControl using code behind? I would like to reuse the methods in the TabItem from multiple UserControls.
var subSystem = new SIASystemTab(opCo);
var configTab = new ConfigTab()
{
Header = "New Header*",
Content = subSystem
};
One simple way is to create a property in SIASystemTab like this
public ConfigTab myConfigTab {get; set;}
Then assign the ConfigTab instance to this property
subSystem.myConfigTab = configTab;
Later on u can use this as per your need
Cast the Content property of the UserControl to ConfigTab:
var tab = this.Content as ConfigTab;
var siaSystemTab = tab.Content;

Binding to a value of a string property

Is there anyway to bind to the value of a property, not property itself.
For example: There is a generic grid with two columns "Name" and "Code"
In viewmodel:
NameMemberPath = "Title"; // fetch from database
CodeMemberPath = "ProductCode"; // fetch from database
In Xaml:
<telerik:GridViewDataColumn UniqueName="Name" DataMemberBinding="{Binding Path=NameMemberPath}" />
<telerik:GridViewDataColumn UniqueName="Code" DataMemberBinding="{Binding Path=CodeMemberPath}" />
How to bind the Name to "Title" insted of NameMemberPath
It's possible to do it programmatically but I need to do it declaratively!
i would suggest to change your concept because the ViewModel should provides the Properties for the View directly
let's suggest you want a generic View which will bind to a Property MyAnyProb so it is now to problem of your ViewModel to present this Property.
your ViewModel does now his job by providing this property
public object MyAnyProb
{
get { return getMagic(); }
set { setMagic(value); }
}
// and her is the part where you need to add your logic
private object getMagic()
{
// let magic happen
}
private void setMagic(object probValue)
{
// other magic
}
now you are able to use your view generic with no worries about the property because your generic ViewModel will take care about it
for example:
var MyStrings = new List<string>();
MyStrings = MyFunctionToRetrieveAListOfStrings();
foreach(var str in MyStrings)
{
Binding binding = new Binding("YourControlValue");
binding.Source = str;
YourControl.SetBinding(TextBlock.TextProperty, binding)
}
http://msdn.microsoft.com/en-us/library/ms742863.aspx
IMHO you cannot do that in xaml. How about adding columns to your telerik grid from code behind? I am not very sure if this solution is feasible to you or not but worth a try.
GridViewDataColumn column = new GridViewDataColumn();
column.DataMemberBinding = new Binding(CodeMemberPath.ToString());
this.yourTelerikGrid.Columns.Add(column);
Hope this helps.
The key is to use the "SetBinding" method.
TextBlock myTextBlock = new TextBlock();
myTextBlock.SetBinding(TextBlock.TextProperty, new Binding("SomePropertyName"));
That should do the trick
No you always bind a DependencyProperty to a (public) Property.
(source: microsoft.com)
Read more about Binding in the MSDN!

TextBox inside a listview cell

I have a listview that I would like to add a textbox inside each gridview column cell so I can type data into it and then fetch that data.
I'm creating a datatemplate and passing it to a cell template for the GridViewColumn but when I look at the listview I can't add anything to the cell. It doesn't look like the textbox was even created.
GridViewColumn conceptColumn = new GridViewColumn();
conceptColumn.Header = conceptName;
conceptColumn.CellTemplate = this.GetDataTemplate();
this.TestModeler.Columns.Add(conceptColumn);
conceptColumn.DisplayMemberBinding = new Binding(conceptName);
private DataTemplate GetDataTemplate()
{
DataTemplate dt = new DataTemplate(typeof(TextBox));
FrameworkElementFactory txtElement = new FrameworkElementFactory(typeof(TextBox));
dt.VisualTree = txtElement;
Binding bind = new Binding();
bind.Path = new PropertyPath("Text");
bind.Mode = BindingMode.TwoWay;
txtElement.SetBinding(TextBox.TextProperty, bind);
txtElement.SetValue(TextBox.TextProperty, "test");
return dt;
}
Please take a look at the ListView Class page at MSDN where you can find a XAML example and plenty of link on how to do various things with a WPF ListView.
Of particular interest to you, please take a look at the How to: Use Templates to Style a ListView That Uses GridView page there which explains what you are trying to do (but in XAML) with examples.
MSDN should always be your first place to look as it is full of information just waiting to be read.

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.

WPF Bind control to DataView

I am having a LOT of trouble trying to bind my controls to a data source. I tried binding to XML document. That worked, but lots of issues when I tried to refresh the XML document itself and have it update the UI.
My newest try is to bind my controls to a DataView, which seems simple. I have a sample app I found here on StackOverflow, which does this:
public MainWindow()
{
InitializeComponent();
DataTable dataTable = GetTable();
Binding dataTableBinding = new Binding();
dataTableBinding.Source = dataTable;
dataTableBinding.Path = new PropertyPath("Rows[0][MyTextColumn]");
txtMyTextColumnDataTable.SetBinding(TextBox.TextProperty, dataTableBinding);
DataView dataView = dataTable.DefaultView;
Binding dataViewBinding = new Binding();
dataViewBinding.Source = dataView;
dataViewBinding.Path = new PropertyPath("[0][MyTextColumn]");
txtMyTextColumnDataView.SetBinding(TextBox.TextProperty, dataViewBinding);
}
This works perfectly, right out of the box. I added a button whose code updates the value in the data table, and the textbox immediately reflects the new value when I click that button.
I tried this in my VB.Net project, like this:
dim plcData As DataTable = GetTable()
dim plcView As DataView = plcData.DefaultView
dim plcBinding As Binding = New Binding
plcBinding.Source = plcView
plcBinding.Path = New PropertyPath("(0)(conveyor_plc_data_Main_FeedCarousel_caroAngle)")
Me.tb.SetBinding(TextBlock.TextProperty, plcBinding)
And it doesn't work. It will not update my UI control.
In both cases, GetTable builds a 1-row DataTable with sample data. In my VB project, tb is a TextBlock on my MainWindow.
In the VB project, I can interrupt my code and query the particular data column in the Immediate window, and the proper value is there. It just won't update into my control.
This seems like a very simple thing to do. I am quite new to WPF, and can't see what is wrong with my code. Eventually I would like to define the binding in my XAML, but can't figure out how to do this. At this point, a code-behind setting of the binding would be ok. I will have many controls to be bound to many data columns.
Can anybody tell me what obvious thing I'm missing here?
According to the documentation, the syntax for the PropertyPath class only accepts C#-style indexers.
Single Indexer on the Immediate Object as Data Context:
<Binding Path="[key]" .../>
The class has no way to change its syntax based on the calling language.
EDIT
To set the binding in XAML when the DataView is created in the code-behind, expose the view as a property:
public static readonly DependencyProperty plcViewProperty
= DependencyProperty.Register("plcView", typeof(System.Data.DataView),
typeof(MainWindow), new PropertyMetadata(null));
public System.Data.DataView plcView
{
get { return (System.Data.DataView)GetValue(plcViewProperty); }
set { SetValue(plcViewProperty, value); }
}
private void MainWindow_Initialized(object sender, EventArgs eventArgs)
{
plcView = GetTable().DefaultView;
}
Then in your XAML:
<Window x:Name="TheWindow" ...>
...
Text="{Binding ElementName=TheWindow,
Path=plcView[0][conveyor_plc_data_Main_FeedCarousel_caroAngle]}"

Resources