DataGrid Combobox SelectedValue - c#

I've written a simple example in which a DataGrid on a WPF form is populated entirely from the codebehind. A DataGridTemplateColumn with a ComboBox has the ItemsSource set to a DummyClass that contains two properties for the DisplayMember and the SelectedValue.
A DataTable is populated with a single column with two rows. The ItemsSource for the DataGrid is set to the default view of the DataTable.
When the code runs, each ComboBox in the DataGrid displays correctly and has the proper options available in the dropdown but does not display the values from the DataTable.
What binding am I missing to connect the ComboBox SelectedValue to the values from the DataTable?
public partial class MainWindow : Window
{
public class DummyClass
{
public int SelectedValue { get; set; }
public string DisplayValue { get; set; }
}
public ObservableCollection<DummyClass> DummyClassCollection;
public MainWindow()
{
InitializeComponent();
DummyClassCollection = new ObservableCollection<DummyClass>();
DummyClassCollection.Add(new DummyClass() { DisplayValue = "Item1", SelectedValue = 0 });
DummyClassCollection.Add(new DummyClass() { DisplayValue = "Item2", SelectedValue = 1 });
DummyClassCollection.Add(new DummyClass() { DisplayValue = "Item3", SelectedValue = 2 });
DataGridTemplateColumn templateColumn = new DataGridTemplateColumn();
DataTemplate dataTemplate = new DataTemplate();
FrameworkElementFactory control = new FrameworkElementFactory(typeof(ComboBox));
control.SetValue(ComboBox.ItemsSourceProperty, DummyClassCollection);
control.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayValue");
//
//Some binding to connect ComboBox Selectedvalue to DataTable values
//
dataTemplate.VisualTree = control;
templateColumn.CellTemplate = dataTemplate;
templateColumn.Header = "DummyColumn";
dgGrid.Columns.Add(templateColumn);
DataTable table = new DataTable();
table.Columns.Add("DummyColumn");
table.Rows.Add(1);
table.Rows.Add(2);
dgGrid.AutoGenerateColumns = false;
dgGrid.ItemsSource = table.DefaultView;
}
}

Here is all you need...
control.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayValue");
control.SetValue(ComboBox.SelectedValuePathProperty, "SelectedValue");
control.SetValue(ComboBox.SelectedValueProperty, new Binding("DummyColumn"));

Related

Binding String property to TextBox Text from Code Behind

Sorry for this basic question
I have a data model :
class data_test
{
public string textdata { get; set; }
public bool booldata { get; set; }
public bool checkdata { get; set; }
public data_opt enumdata { get; set; }
}
Here's Enum :
enum data_opt
{
managed = 1,
unmanaged = 2 ,
mixed = 3
}
Then I create a data model :
var n_Data = new data_test()
{ textdata = "test data",
booldata = false,
checkdata = true ,
enumdata = data_opt.mixed
};
And I create a text box from code behind :
var text_box = new TextBox();
Now I want to bind text_box.Text property to n_Data.textdata from code behind
The same way DataGrid works , two-way connection with real-time update.
I found some pages :
Binding String Property in Code-Behind TextBlock
WPF Data Binding to a string property
Binding string property to object
Unfortunately , none of them worked for me , Here's my code to bind:
Binding binding = new Binding();
binding.Path = new PropertyPath("textdata");
binding.Source = n_Data;
text_box.SetBinding(TextBlock.TextProperty, binding);
Also I tried this :
Binding binding = new Binding();
binding.Path = new PropertyPath("textdata");
binding.Source = n_Data;
BindingOperations.SetBinding(text_box, TextBlock.TextProperty, binding);
Both of them don't work , What am I doing wrong ?
Since your target is a TextBox, you can't use TextBlock.TextProperty as property to bind. You need to use TextBox.TextProperty:
text_box.SetBinding(TextBox.TextProperty, binding);

ASP.NET web control drop down list object population

I'm using ASP.NET to create a dynamic web form with variable controls. Some of the controls that I want to create are dropdownlists, and I would like them to be populated with certain custom subitems. How can I do this? I'm unable to populate the ddl with the subitems themselves (they are not of string type), but am also unable to populate the ddl with a string member variable (subitem.displayName) without losing the entire subitem. Here is some code for reference:
public class SubItem
{
string displayName;
string value;
...
}
At first I tried to add the objects to the ddl directly:
DropDownList x;
x.ItemType = SubItem; //error "type not valid in this context"
x.Add(subitem); // error
Ideally, I could solve this by displaying subitem.name in the ddl, but with the functionality of a subitem being parsed, so that in an event handler I can access all of the subitem's properties. Is there something like the following that exists?
DropDownList x;
x.ItemType = SubItem;
x.DisplayType = SubItem.displayName;
x.Items.Add(subitem);
Thanks in advance!
You can only bind something do a DropDownList that has and IEnumerable interface. Like a List or Array.
//create a new list of SubItem
List<SubItem> SubItems = new List<SubItem>();
//add some data
SubItems.Add(new SubItem() { displayName = "Test 1", value = "1" });
SubItems.Add(new SubItem() { displayName = "Test 2", value = "2" });
SubItems.Add(new SubItem() { displayName = "Test 3", value = "3" });
//create the dropdownlist and bind the data
DropDownList x = new DropDownList();
x.DataSource = SubItems;
x.DataValueField = "value";
x.DataTextField = "displayName";
x.DataBind();
//put the dropdownlist on the page
PlaceHolder1.Controls.Add(x);
With the class
public class SubItem
{
public string value { get; set; }
public string displayName { get; set; }
}

Add image to ListView C# WPF (without xaml)

How can I make an image item in ListView? I need to do it without xaml, only C#. I was surfing about 40 min about it and have nothin found.
I've tried a lot of things and i stopped here
in first column i see just "System.Windows.Controls.StackPanel".
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
GridView grView = new GridView();
GridViewColumn gwCol1 = new GridViewColumn();
GridViewColumn gwCol2 = new GridViewColumn();
gwCol1.Header = "Avatar";
gwCol2.Header = "Name";
gwCol2.DisplayMemberBinding = new Binding("name");
gwCol1.DisplayMemberBinding = new Binding("stack");
grView.Columns.Add(gwCol1);
grView.Columns.Add(gwCol2);
listView1.View = grView;
//
var list = new List<XData>();
listView1.ItemsSource = list;
//
BitmapImage image1 = new BitmapImage(new Uri(#"C:\Users\montana\OneDrive\Pictures\Saved Pictures\WVQfZqY.jpg"));
Image img = new Image();
img.Width = 100;
img.Height = 100;
img.Source = image1;
StackPanel stackPanel1 = new StackPanel();
stackPanel1.Orientation = Orientation.Horizontal;
stackPanel1.Children.Add(img);
list.Add(new XData() { name="hola", stack=stackPanel1 });
}
}
class XData
{
public string name { get; set; }
// public string url { get; set; }
public StackPanel stack { get; set; }
}
Here is something what produce wanted result.
Change XData definition to avoid having view elements there (you didn't mention MVVM, but it's good to stick to):
class XData
{
public string Name { get; set; }
public string Path { get; set; }
}
Now you can either define data template in xaml (common solution) or generate it in code behind like this:
var factory = new FrameworkElementFactory(typeof(Image));
factory.SetValue(Image.SourceProperty, new Binding(nameof(XData.Path)));
factory.SetValue(Image.WidthProperty, 100.0);
factory.SetValue(Image.HeightProperty, 100.0);
var dataTemplate = new DataTemplate { VisualTree = factory };
Data template can be as complicated as you like, but obviously defining it in xaml and then loading with FindResource() is way easier, consider to use this option instead.
And then this datatemplate has to be specified as CellTemplate like this:
GridView grView = new GridView();
grView.Columns.Add(new GridViewColumn { Header = "Avatar", CellTemplate = dataTemplate });
grView.Columns.Add(new GridViewColumn { Header = "Name", DisplayMemberBinding = new Binding(nameof(XData.Name)) });
listView1.View = grView;
Note: you shouldn't use DisplayMemberBinding for column with CellTemplate.
Now, finally, you can fill ListView by setting its ItemSource as usual:
var list = new List<XData>();
list.Add(new XData { Name = "hola", Path = #"c:\temp\1.jpg" });
list.Add(new XData { Name = "hola2", Path = #"c:\temp\2.png" });
listView1.ItemsSource = list;

Custom data binding on ComboBox

I am trying to fill a ComboBox with multiple instances of a custom ComboBoxItem class. The ComboBoxItem class looks like this:
class ComboBoxItem
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Text;
}
}
I can fill the CombBox and read it's values just fine. My only problem is when an existing item comes in, the values should be bound to my ComboBox. But I don't know how to tell the Binding that it should use ComboBoxItem.Value as Value field.
//what to put in place of "SelectedItem"??
comboBox.DataBindings.Add(new Binding("SelectedItem", row, "F_KundenId", true, DataSourceUpdateMode.OnPropertyChanged));
This is how I bind all my Windows ComboBoxes in my app:
First use this to load your dataSource, in this case a List:
public static void LoadComboBox(ComboBox comboBox, object dataSource, string valueMember, string displayMember)
{
comboBox.DataSource = dataSource;
comboBox.ValueMember = valueMember;
comboBox.DisplayMember = displayMember;
}
Then use this to bind the selected value to your "row" column "F_KundenId":
public static void BindComboBox(ComboBox comboBox, object boundDataSource, string boundDataMember)
{
comboBox.DataBindings.Clear();
comboBox.DataBindings.Add("SelectedValue", boundDataSource, boundDataMember);
}
And here is a helper method to do both in a single call:
public static void LoadAndBindComboBox(ComboBox comboBox, object dataSource, string valueMember, string displayMember,
object boundDataSource, string boundDataMember)
{
LoadComboBox(comboBox, dataSource, valueMember, displayMember);
BindComboBox(comboBox, boundDataSource, boundDataMember);
}
This code can be used with ANY datasources you want, and can bind to any column of a DataTable, DataRow or object.
Example:
LoadAndBindComboBox(comboBox, myItems, "Value", "Text", row, "F_KundenId");
Ok, alternatively to Mangist's answer, I have come up with a solution of my own. No need for any custom class. Just use Dictionary<Key, Value>. The only thing is that you have to be careful WHEN during runtime you set DisplayMember and ValueMember. If you reset the DataSource of the ComboBox (set it to null and rebind it), then you need to also set the two Member properties. Then just bind the Dictionary<Key, Value> to the ComboBox using a BindingSource object.
private void InitCombos()
{
Dictionary<string, int> items = GetItems();
combo.DisplayMember = "Key";
combo.ValueMember = "Value";
combo.DataSource = new BindingSource(items, null);
}
//This was where my problem was. I didn't set the two Member properties of my ComboBox,
//thus preventing correct rebinding of DataSource
public void combo2_SelectedIndexChanged(object sender, EventArgs e)
{
combo.DataSource = null;
Dictionary<string, int> newItems = GetItems();
combo.DisplayMember = "Key";
combo.ValueMember = "Value";
combo.DataSource = new BindingSource(items, null);
}

DataGridColumn Binding with Dynamically Generated Data

I have a large set of data that is generated from a web service in my program. I need to display this data in a DataGrid, but the returned collections of data all have different formats (One may be 3 columns and the next 7) so I cannot create a specific object to hold this data. I am having trouble getting this information to display. Right now I am trying to use this method. I put the data into a two-dimensional list of KeyValuePairs. The Key being the Column this data would belong to, the Value being the output for that row. This is what I am trying right now.
private void SetDataValuesExecute(List<List<KeyValuePair<string,object>>> Data)
{
ResultsCollection = Data;
ValuesDataGrid.Columns.Clear();
foreach (string colName in Data[0].Select(x => x.Key).ToList())
{
DataGridTextColumn tempCol = new DataGridTextColumn();
tempCol.Header = colName;
Binding bind = new Binding();
bind.Source = ResultsCollection.Select(x => x.FirstOrDefault(y => y.Key == colName).Value.ToString()).ToList();
tempCol.Binding = bind;
ValuesDataGrid.Columns.Add(tempCol);
}
}
The ResultsCollection is a non-volatile variable to be used as the source of my bindings. It is a copy of all of the two-dimensional List data I need to construct the DataGrid.
This looks at the first entry an extracts the Column Header values and creates new columns based on that. The binding statement looks at each Row, grabs data for the specified Column, and tries to set that as the Column's Binding. This allows me to have both the column name and a list of all the data that goes in that column. Unfortunately binding the list of data to the column ends up not displaying any data.
So my question is: How do I need to format my data in order for the Column Binding to actually display data? Am I approaching this situation all wrong? Any help is appreciated as I am quite stumped.
Here's a complete working sample
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var data = new MyViewModel();
int columnIndex = 0;
foreach (var name in data.ColumnNames)
{
grid.Columns.Add(
new DataGridTextColumn
{
Header = name,
Binding = new Binding(
string.Format("Values[{0}]", columnIndex++))
});
}
DataContext = data;
}
}
public class MyViewModel
{
public MyViewModel()
{
Items = new List<RowDataItem>
{
new RowDataItem(),
new RowDataItem(),
new RowDataItem(),
};
ColumnNames = new List<string>{ "Col 1", "Col 2", "Col 3"};
}
public IList<string> ColumnNames { get; private set; }
public IList<RowDataItem> Items { get; private set; }
}
public class RowDataItem
{
public RowDataItem()
{
Values = new List<string>{ "One", "Two", "Three"};
}
public IList<string> Values { get; private set; }
}
The Xaml
<Grid>
<DataGrid x:Name="grid" ItemsSource="{Binding Items}"
AutoGenerateColumns="False"/>
</Grid>
This is a GridView but it works. I think you need to use bind.Path but with a KVP not sure about the rest of the syntax.
WPF - Display Grid of Results With Dynamic Columns/Rows

Categories