In my current windows application I am looking on how to give a datasource to my usercontrol.
On my page I add my own usercontrol in a flowlayoutpanel, the usercontrol has 3 textboxes in it which I want to fill with data from a datasource.
usercontrol uc = new usercontrol();
flowlayoutpanel.Controls.Add(uc);
uc.DataSource?
I know that in silverlight and ASP.NET you can add a datasource to a usercontrol. In the usercontrol you get the data into the textboxes by using {Binding fieldname} as their content. I can't find any information on this for Windows Forms.
Thanks for the help.
Thomas
There's an article on MSDN which might help you implement this - Walkthrough: Creating a User Control that Supports Simple Data Binding (see also Complex and Lookup Data binding walkthroughs).
I solved this (thanks to the link of Stuart) by putting setters and getters in my usercontrol.
public partial class ucOpleiding : UserControl
{
public string Datum
{
get { return txtDatum.Text; }
set { txtDatum.Text = value; }
}
public string Plaats
{
get { return txtPlaats.Text; }
set { txtPlaats.Text = value; }
}
public string Omschrijving
{
get { return txtOmschrijving.Text; }
set { txtOmschrijving.Text = value; }
}
public ucOpleiding()
{
InitializeComponent();
}
And in my main form I will then call those setters and getters.
foreach (opleiding opl in ChauffeurManagement.getOpleidingen(Int32.Parse(cbbID.SelectedValue.ToString())))
{
ucOpleiding uc = new ucOpleiding();
uc.Datum = opl.datum.ToString();
uc.Plaats = opl.plaats_instantie;
uc.Omschrijving = opl.omschrijving;
flpOpleidingen.Controls.Add(uc);
}
Related
I have here some custom user control with DataGridView in it, now when i Implement my user control to some form I want to be able to access DataGridView properties within designer, is this possible?
This is my user control
public partial class MyUserControlTest01 : UserControl
{
// my way to accsses DataGridView
//
public DataGridView Dtv_userControl
{
get { return myUserControl_datagridView; }
set { myUserControl_datagridView = value; }
}
public MyUserControlTest01()
{
InitializeComponent();
}
So when i implement this user control to some Form, I can access DataGridView properties from code, but i want to do it from Designer.
Hope my question is clear,
any suggestion is helpful.
Thank you for your time.
Just add these annotations over your DataGridView-Property
[Browsable(true)]
[Category("*Any category you want*")]
public DataGridView Dtv_userControl
{
get { return myUserControl_datagridView; }
set { myUserControl_datagridView = value; }
}
I'm implementing MVVM for a WPF application.
The ViewModels are created as follows:
ViewModel: base class from which all ViewModels override
MainTemplateViewModel: the 'Masterpage' ViewModel which contains a ViewModel property Current that contains the ViewModel to show
CustomerOverviewViewModel: an example of a view that can be placed in the MainTemplateViewModel.Current
The CustomerGridViewModel contains a Telerik GridView. I would like to show the number of items in the title of the MainTemplateViewModel. The GridView.Items.Count property implements the INotifyPropertyChanged so I would like to bind this property to ViewModel.RowCount (because the CustomerGridViewModel doesn't know it is part of the MainTemplateViewModel it cannot be bound directly to the TextBlock). I can in turn use ViewModel.NumberOfRecords to show the amount in the title.
How can I bind the Count property to a property in my ViewModel?
Edit
I'll describe the issue in more detail:
The list of objects shown in the grid is a binding from the ViewModel:
<telerik:RadGridView x:Name="CustomerGrid" ItemsSource="{Binding CustomerViewModels}">
</telerik:RadGridView>
When filtering the Grid in memory, the Telerik Grid automatically changes the GridView.Items.Count property (this does not mean the original list count is changed!). So if I can bind this property to a property in the ViewModel class, this would solve the problem.
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
private int numberOfRecords;
public int NumberOfRecords
{
get { return numberOfRecords; }
set { numberOfRecords = value; OnPropertyChanged(); }
}
}
MainTemplateViewModel.cs
public class MainTemplateViewModel : ViewModel
{
private ViewModel current = new MainOverviewViewModel();
public ViewModel Current
{
get { return current; }
set
{
if (current != value)
{
current = value; OnPropertyChanged();
}
}
}
}
CustomerOverview.xaml.cs
public partial class CustomerOverview : UserControl
{
public CustomerOverview()
{
InitializeComponent();
this.CustomerGrid.Items.CollectionChanged += ItemsCollectionChanged;
this.CustomerGrid.Loaded += CustomerGrid_Loaded;
}
void CustomerGrid_Loaded(object sender, RoutedEventArgs e)
{
/* METHOD 1 PROBLEM: the field to bind to in the MainTemplate is out of scope and accessing a view is not MVVM */
var binding = new Binding();
binding.Path = new PropertyPath("Items.Count");
binding.Source = CustomerGrid;
((MainWindow)this.ParentOfType<MainWindow>()).NumberOfRecords.SetBinding(TextBlock.TextProperty, binding);
}
void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
/* METHOD 2 PROBLEM: codebehind code should be in viewmodel */
((CustomerOverviewViewModel)this.DataContext).NumberOfRecords = CustomerGrid.Items.Count;
}
}
Instead of loading the data in your UserControl, just declare a DependencyProperty of the relevant type in it. You can then load the data in the main view model and simply data bind to it from the UserControl. You could do something like this simple example:
In CustomerOverview.xaml.cs:
public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items",
typeof(ObservableCollection<YourDataType>), typeof(CustomerOverview),
new PropertyMetadata(null));
...
In CustomerOverview.xaml:
<ListView ItemsSource="{Binding Items, RelativeSource={RelativeSource AncestorType={
x:Type YourPrefix:CustomerOverview}}}" ... />
...
In MainWindow.xaml (or whichever relevant view):
<YourPrefix:CustomerOverview
Items="{Binding SomeCollectionPropertyInMainTemplateViewModel}" ... />
...
In MainTemplateViewModel.cs (or whichever relevant view model):
public ObservableCollection<YourDataType> SomeCollectionPropertyInMainTemplateViewModel
{
get { return someCollectionPropertyInMainTemplateViewModel; }
set
{
someCollectionPropertyInMainTemplateViewModel = value;
NotifyPropertyChanged("SomeCollectionPropertyInMainTemplateViewModel");
NotifyPropertyChanged("NumberOfRecords");
}
}
public int NumberOfRecords
{
get { return someCollectionPropertyInMainTemplateViewModel.Count; }
}
Telerik Grid has two properties
Visible Count
TelerikGrid.Items.Count
Total Count
TelerikGrid.Items.TotalItemCount
In case this helps!
If i get you right, you want your master to show details of the child.
Your master should be able to know your child by your Current property.
If you are using MVVM correctly, the data bound to your grid comes from the child-ViewModel.
In that case, you have already have the itemscount in your child-ViewModel.
After this you can say in your Master something like
<Label Content="{Binding Current.NumberOfRows}"></Label>
According to this page you could wrap your source in a QueryableCollectionView
I've done some extensive searching before finally deciding to ask this question. I've followed the MSDN tutorials on creating User Controls that use Simple, Complex and Lookup Data Binding.
Walkthrough: Creating a User Control that Supports Simple Data Binding
Walkthrough: Creating a User Control that Supports Complex Data Binding
Walkthrough: Creating a User Control that Supports Lookup Data Binding
And they work great...for a User Control that only uses a single Combobox or Gridview.
Now I want to create a User Control with three different Comboboxes. I want to bind each one to a different Table. The tables are 'Names', 'Types', and 'Products'.
The MSDN tutorials involve creating DataBindingProperties for a single Combobox, but do not show how to do the same for a user control that contains more than one.
using System.Windows.Forms;
namespace CS
{
[System.ComponentModel.LookupBindingProperties(
"DataSource", "DisplayMember", "ValueMember", "LookupMember")]
public partial class LookupBox : UserControl
{
public object DataSource
{
get{ return comboBox1.DataSource; }
set{ comboBox1.DataSource = value; }
}
public string DisplayMember
{
get{ return comboBox1.DisplayMember; }
set{ comboBox1.DisplayMember = value; }
}
public string ValueMember
{
get{ return comboBox1.ValueMember; }
set{ comboBox1.ValueMember = value; }
}
public string LookupMember
{
get{ return comboBox1.SelectedValue.ToString(); }
set{ comboBox1.SelectedValue = value; }
}
public LookupBox()
{
InitializeComponent();
}
}
}
Now, as you can see, there is only one Combobox mentioned in the code. I need to have three Comboboxes, each bound to a different table as mentioned above.
Please, I'm banging my head against the wall. I'm not too well versed in User Controls (although I have used them in ASP.NET), but it seems like a good idea make one since I'm going to be using these three Comboboxes together quite a lot in different places in my application.
You can simply extrapolate what you know with what you need:
public object DataSource1
{
get{ return comboBox1.DataSource; }
set{ comboBox1.DataSource = value; }
}
public object DataSource2
{
get{ return comboBox2.DataSource; }
set{ comboBox2.DataSource = value; }
}
public object DataSource3
{
get{ return comboBox3.DataSource; }
set{ comboBox3.DataSource = value; }
}
Though you probably want to make better descriptive names than ..1, ..2, ..3.
I would create a UserControl that contained three of your LookupBox's. For example:
public partial class MyLookupBoxes : UserControl
{
public LookupBox()
{
// Add the 3 LookupBox to this UserControl using the designer
InitializeComponent();
SetupDataSources();
}
private void SetupDataSources()
{
namesLookupBox1.DataSource = names_data_source_1;
// ...
typesLookupBox2.DataSource = types_data_srouce_2;
// ...
productsLookupBox3.DataSource = products_data_srouce_2;
// ...
}
}
I have a list of items with id and description(i can introduce key-value collection instead if needed). What i need is control that binded to viewmodel id property, but shows description of corresponding item/pair on it. Closest example i know is combobox, where i set DisplayMemberPath and SelectedValue/SelectedValuePath, but i don't need dropdown. So is there any in-built control in Silverlight for this?
(of course i can code one myself, it's easy and I can even just put some logic for viewmodel to get pair i need and bind it's description to simple textblock)
Edit: To illustrate what funcionality i need i coded simple example class. It actually satisfies my needs, but i still want to know if i can use built-in control.
public class CollectionItemDisplayControl:TextBox
{
public CollectionItemDisplayControl()
{
IsReadOnly = true;
}
public string SelectedID
{
get { return (string)GetValue(SelectedIDProperty); }
set { SetValue(SelectedIDProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedID. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedIDProperty =
DependencyProperty.Register("SelectedID", typeof(string), typeof(CollectionItemDisplayControl), new PropertyMetadata(new PropertyChangedCallback(OnSelectedIDChangedStatic)));
private static void OnSelectedIDChangedStatic(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CollectionItemDisplayControl originator = d as CollectionItemDisplayControl;
if (originator != null)
{
originator.OnSelectedIDChanged(e);
}
}
private void OnSelectedIDChanged(DependencyPropertyChangedEventArgs e)
{
string description = String.Empty;
string value = e.NewValue as string;
if (value != null)
{
foreach (var item in _items)
{
if (item.UniqueID == value)
{
description = item.Description;
break;
}
}
}
Text = description;
}
private IDataCollection _viewModel;
public IDataCollection ViewModel
{
get { return _viewModel; }
set
{
_viewModel = value;
if (_viewModel != null)
{
_items = _viewModel.Items;
}
}
}
private ObservableCollection<IUnique> _items = new ObservableCollection<IUnique>();
}
ItemClass contains two properties: ID and Description. I can place this control on the page, bind Items, and one-way bind SelectedID.
Edit 2: well i didn't make SelectedID DependencyProperty so binding won't work, but i will fix it right away
Edit 3: first snippet was sloppy and didn't work properly, so i fixed it.
If I understood properly,
You just need the right binding implemented.
(you do need a list? not just a single item, even if single it's similar just any control)
Bind the list to e.g. ItemsControl.
Set ItemsSource to your list of items
Then override ToString on your Item providing it's 'yours' really. If not you can make your own wrapper.
Within ToString output whatever is presenting your item, e.g. description.
That's a quickest solution, you can also make item template as you want.
EDIT:
well just put everything in the view model and bind to it - the TextBox, i.e.
Text={Binding SelectedText}
e.g.
...in your view model add SelectedText and SelectedID (and Items if needed) - properly do OnPropertyChanged.
Set SelectedID from view model or if 'bound' from another control that may change it.
Within set for SelectedID set the SelectedText.
No need for a control for things like that, it's all data binding really.
I want to add complex databinding to my custom winforms control, so I can do the following:
myControl.DisplayMember = "Name";
myControl.ValueMember = "Name";
myControl.DataSource = new List<someObject>();
Does anyone know what interfaces, etc. have to be implemented to achieve this?
I have had a look into it and all I found is IBindableComponent, but that seems to be for Simple Binding rather than Complex Binding.
Apply one of the following attributes to your custom control, depending on which kind of data binding you need:
For complex data binding: ComplexBindingPropertiesAttribute
For lookup data binding: LookupBindingPropertiesAttribute
(The question specifically mentions complex data binding, but the given code example looks like lookup data binding to me, so I have included both.)
For example implementations, look at the .NET Framework source code:
ComplexBindindPropertiesAttribute implementation in DataGridView
LookupBindingPropertiesAttribute implementation in ListControl
But those implementations look very complicated to me, so it might be easier to embed an existing control (such as a DataGridView, ListBox or ComboBox) within your own custom control to take advantage of its existing data binding implementation, rather than writing your own. (You could make the embedded control invisible if necessary.) That is the approach demonstrated by Microsoft in the following guides:
Create a Windows Forms user control that supports complex data binding
Create a Windows Forms user control that supports lookup data binding
In those guides, they create a data source to bind the custom control to an external database, but it looks like you're simply trying to bind your custom control to an internal collection such as a List<T>. In that case, the adapted code below might work for you.
In a Windows Forms project in Visual Studio, add a new UserControl.
For complex data binding, apply the ComplexBindingPropertiesAttribute to the custom control. Add a DataGridView control to it. Add DataSource and DataMember properties, and hook them into the DataGridView's own properties.
// ComplexBindingControl.cs
// Adapted from https://learn.microsoft.com/visualstudio/data-tools/create-a-windows-forms-user-control-that-supports-complex-data-binding
using System.ComponentModel;
using System.Windows.Forms;
namespace BindingDemo
{
[ComplexBindingProperties("DataSource", "DataMember")]
public partial class ComplexBindingControl : UserControl
{
public ComplexBindingControl()
{
InitializeComponent();
}
// Use a DataGridView for its complex data binding implementation.
public object DataSource
{
get => dataGridView1.DataSource;
set => dataGridView1.DataSource = value;
}
public string DataMember
{
get => dataGridView1.DataMember;
set => dataGridView1.DataMember = value;
}
}
}
For lookup data binding, apply the LookupBindingPropertiesAttribute to the custom control. Add a ListBox or ComboBox control to it. Add DataSource, DisplayMember, ValueMember and LookupMember properties, and hook them into the ListBox's or ComboBox's own properties.
// LookupBindingControl.cs
// Adapted from https://learn.microsoft.com/visualstudio/data-tools/create-a-windows-forms-user-control-that-supports-lookup-data-binding
using System.ComponentModel;
using System.Windows.Forms;
namespace BindingDemo
{
[LookupBindingProperties("DataSource", "DisplayMember", "ValueMember", "LookupMember")]
public partial class LookupBindingControl : UserControl
{
public LookupBindingControl()
{
InitializeComponent();
}
// Use a ListBox or ComboBox for its lookup data binding implementation.
public object DataSource
{
get => listBox1.DataSource;
set => listBox1.DataSource = value;
}
public string DisplayMember
{
get => listBox1.DisplayMember;
set => listBox1.DisplayMember = value;
}
public string ValueMember
{
get => listBox1.ValueMember;
set => listBox1.ValueMember = value;
}
public string LookupMember
{
get => listBox1.SelectedValue?.ToString();
set => listBox1.SelectedValue = value;
}
}
}
(Edit: thanks to Frank's answer for reminding me that listBox1.SelectedValue could be null.)
To test it, build the project in Visual Studio, then add an instance of the custom control to a Form. Create some sample data, and bind it to the custom control using its relevant properties.
// Form1.cs
using System.Collections.Generic;
using System.Windows.Forms;
namespace BindingDemo
{
public partial class Form1 : Form
{
private readonly List<SomeObject> data;
public Form1()
{
InitializeComponent();
// Prepare some sample data.
data = new List<SomeObject>
{
new SomeObject("Alice"),
new SomeObject("Bob"),
new SomeObject("Carol"),
};
// Bind the data to your custom control...
// ...for "complex" data binding:
complexBindingControl1.DataSource = data;
// ...for "lookup" data binding:
lookupBindingControl1.DataSource = data;
lookupBindingControl1.DisplayMember = "Name";
lookupBindingControl1.ValueMember = "Name";
}
}
internal class SomeObject
{
public SomeObject(string name)
{
Name = name;
}
public string Name { get; set; }
}
}
Your class needs to inherit the DataBoundControl class instead of UserControl.
To run the very helpfull example of Chris Tollefson BindingDemo without problems put a try/catch Block around the LookupMember getter like this:
public string LookupMember {
get {
try {
return listBox1.SelectedValue.ToString();
}
catch { return null; }
}
set => listBox1.SelectedValue = value;
}