I want to get into DataBinding and currently I'm stuck. I just can't get it to work. I read many tutorials, but honestly, none of the really helped me. I know what DataBinding is and why it's cool to use it, but I never came across a tutorial that showed me what to do in my code. They all just assume I know what I have to do there and only show the XAML side.
This is my class:
public class Test : Window
{
public IList<String> data { get; set; }
public Test() {
data = new List<String>();
InitializeComponents();
data.Add("Hello");
data.Add("World");
}
}
And here's my XAML
<ListBox HorizontalAlignment="Left" Margin="6,6,0,6"
Name="SourceDocumentsList" Width="202"
ItemsSource="{Binding Source={x:Static Application.Current}, Path=data}" />
Yet, nothing is displayed when I render the window. How can something this easy fail? What am I doing wrong here?
The way I understand it, I tell the Listbox that it should bind itself to the data property of the currently running application, which is my class Test.
The currently running application is not that class, it's just a window, what you bind to is the instance of the App class. You cannot statically get that window instance this way. How the binding should be made depends on where that XAML is (if it is in the Test window you can for example use RelativeSource={RelativeSource AncestorType=Window} instead).
I would recommend reading the MSDN documentation on data binding and this article on debugging.
Move those properties into a separate class like
public class ViewModel
{
public IList<String> Data { get; set; }
public ViewModel()
{
Data = new ObservableCollection<string>();
Data.Add("Hello");
Data.Add("World");
}
}
Change your Window Code Behind as
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
Your Xaml will look less complicated
<ListBox HorizontalAlignment="Left" Margin="6,6,0,6"
Name="SourceDocumentsList" Width="202"
ItemsSource="{Binding Data}" />
This is what we call moving into MVVM pattern. Happy Coding !
Related
I'm begginer at wpf so please be patient with me :)
I have stored 40.000 articles in MySql database, and when I click on a button I'm opening a window that loads that articles, and I did it on this way:
/// <summary>
/// Interaction logic
/// </summary>
public partial class ArticlesAdd : Window
{
public ObservableCollection<MyArticles> articlesList = ObservableCollection<MyArticles>(ArticlesController.SelectAll());
public ArticlesAdd()
{
this.InitializeComponent();
// Setting source to my DATAGRID when this window is loaded/opened
dataGridMyArticles.ItemsSource = articlesList;
}
}
But I saw some examples are setting ItemsSource directly on DataGrid Control like this (IN XAML PART):
<DataGrid Name="dataGridMyArticles" ItemsSource="{Binding Source=articlesList}" AutoGenerateColumns="False">
But I don't know how this works and how this should be implemented because I'm using dataGridMyArticles.ItemsSource = articlesList;
Is that ItemsSource="{Binding Source=articlesList}" on a XAML side faster than my code behind binding ?
and would it IsAsync=True make data binding faster/opens window faster or smth like that?
So how can I bind that list to my DataGrid without using code behind, and is that approach faster than setting DataGrid's source there in my Class constructor.. ?
Thanks guys
Cheers
Binding an element in a view to a source property of a view model is common practice when you follow the Model-View-ViewModel (MVVM) design pattern. MVVM has nothing to do with performance but it is the recommended design pattern to use when developing XAML based UI applications.
It won't make your application faster, but if you do it right it will make the application easier to maintain, test and develop. You can read more about the motivations for implementing an application using MVVM pattern on MSDN: https://msdn.microsoft.com/en-us/library/hh848246.aspx. There are a lot more resources available online if your Google or Bing for it.
In your particular example, you would define a view model class which holds the list of articles:
public class ArticlesViewModel
{
public ObservableCollection<MyArticles> ArticlesList { get; private set; }
public ArticlesViewModel()
{
ArticlesList = ObservableCollection<MyArticles>(ArticlesController.SelectAll());
}
}
Set the DataContext of the view to an instance of this class:
public partial class ArticlesAdd : Window
{
public ArticlesAdd()
{
this.InitializeComponent();
DataContext = new ArticlesViewModel();
}
}
You can then bind to any public property of the DataContext/view model:
<DataGrid Name="dataGridMyArticles" ItemsSource="{Binding Source=ArticlesList}" AutoGenerateColumns="False">
You probably also want to call the ArticlesController.SelectAll() method on a background in order to prevent the UI from freezing during the time it takes to collect the data from the database, but that's another story that is not directly related to MVVM and the use of bindings.
I have some issues with my DependencyProperty in a custom UserControl.
I need to display informations about people in a particular way. To achieve this, I have several UserControls that receive a List<PeopleList> which contains (obviously) one or more People.
Let me show you my (simplified) code and I'll then explain to you the actual behavior of my app.
Here is my UserControl :
public abstract class PeopleLine : UserControl
{
public static readonly DependencyProperty PeopleListProperty =
DependencyProperty.Register("PeopleList", typeof(List<PeopleModel>), typeof(PeopleLine), new PropertyMetadata(default(List<PeopleModel>)));
public List<PeopleModel> PeopleList
{
get { return (List<PeopleModel>)GetValue(PeopleListProperty); }
set { SetValue(PeopleListProperty, value); }
}
}
Then my xaml :
<local:PeopleLine
x:Class="MyApp.Controls.EventSheet.OnePeople"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.Controls.EventSheet"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid
Margin="0 5"
VerticalAlignment="Top"
Height="51">
<TextBlock
Grid.Column="1"
HorizontalAlignment="Center"
Foreground="Red"
FontSize="25"
Text="{Binding PeopleList[0].Name}"/>
</Grid>
</local:PeopleLine>
And this all starts with my Page which contains an ItemsControl with a correct ItemsSource (I already checked it) and an ItemTemplateSelector (also working perfectly). Here is one of the DataTemplate used by the selector :
<DataTemplate x:Key="OnePeople">
<peoplecontrols:OnePeople
PeopleList="{Binding LinePeopleList}"/>
</DataTemplate>
I'm using several Models That are not really important here since I simplified my code to only have the most important information.
So, back to my issue. When replacing the peoplecontrols:OnePeople in the selector's DataTemplate by a string and putting LinePeopleList[0].Nameas Text, I have the correct text displayed, proving me that my data is correct at this point.
Problem is that when putting back my peoplecontrols:OnePeople, my DependencyProperty is never set. I put a breakpoint at PeopleList's setter and it never triggers.
I tried several modifications (especially those that are given in this post, so replacing the typeof(List<PeopleModel>)by typeof(object) has already been tried) with no success. Also, I tried to replace my DependencyProperty to a string and directly send the name in the DataTemplate but the setter is still not called...
I have no more ideas now and don't understand what's wrong with my code. Any help would be greatly appreciated.
Thanks in advance.
Thomas
Try adding the following line in your UserControl's Constructor, after the call to InitializeComponent:
(this.Content as FrameworkElement).DataContext = this;
I created a sample app on regarding this. Hopefully it reflects your situation correctly:
https://github.com/mikoskinen/uwpusercontrollistdp
If you clone the app and run it, you'll notice that the binding doesn't work. But if you uncomment the Datacontext = this line from UserControl, everything should work OK. Here's working code:
public PeopleLine()
{
this.InitializeComponent();
(this.Content as FrameworkElement).DataContext = this;
}
I've just started taking up a course about WPF and I'm a bit confuse about some areas related to Data-Binding. I have no syntax issue, but most probably committed some newbie errors and I have couple of questions.
I've done a simple screen with 2 textboxes and I when I click a button these two items are added to a ListBox.
Reference within the Window tag of the XAML to the People class
xmlns:classes="clr-namespace:WPF_Course.Classes"
Added a Window resource
<Window.Resources>
<classes:People x:Key="people"/>
</Window.Resources>
Here's how I've declared my Listbox
<ListBox DataContext="{Binding Source={StaticResource people}}"
ItemsSource="{Binding Persons}"
x:Name="PersonListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel>
<TextBlock Text="{Binding FullName}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So, I've added a DataContext to my ListBox where I bind it to my people resource and also I add an ItemSource which looks on a property within my People .
This is my class
public class People : ObservableCollection<Person>
{
public ObservableCollection<Person> Persons { get { return persons; } set { persons = value; } }
private ObservableCollection<Person> persons = new ObservableCollection<Person>();
public People()
{
for (int i = 0; i < 1; i++)
{
// implicitly I add one item just for messing around with the constructor
Persons.Add(new Person()
{
Name = "Dummy",
LastName = "Dummy",
Age = 15
});
}
}
}
Based on what I've done so far I have the following questions :
1) What's the difference between (they have the same effect, but there's more reasoning behind it ? )
ItemsSource = "{Binding Persons}"
and
ItemsSource = "{Binding Path = Persons }"
Also by leaving the ItemSource = "{Binding}" am I actually just instantiating the a People instance, thus all my logic being treated from the constructor of that class ? I've messed around with it and it appears to do so, but I am not sure.
2) On my Peoples class I've Implemented the ObservableCollection<Person> (where Person is also a class). Initially I was doing a static addition to my list from the constructor itself and I had no properties defined within the class ( ObservableCollection<person> type of properties ) thus needing it ( the implementatiton of the interface) but now using a property do I really need it? , so my question is :
If my class's sole purpose is to load things within it's collection from the constructor only ( and not from an outside class, thus needing some sort of a property ), is it a best practice to implement my class with the ObservableCollection<myClass> or to define properties of the same type that I've done ? (for accessing from an outside class)
I am sorry for the weird questions because I know they sound somewhat silly, I'm looking from a validation because I've just started working with wpf recently.
Thanks
Edit 2 : Thank you for all your answers, I understood now. Also I've forgotten to show you how I insert data in my collection. ( Added this edit for me to remember if I forget it and for others that may stumble upon this thread having a similar confusion )
ObservableCollection<Person> ppl;
public MainWindow()
{
InitializeComponent();
person = new Person();
stackPanelPerson.DataContext = person;
people = new People();
ppl = people.Persons;
PersonListBox.ItemsSource = ppl;
}
Initially I was doing like this
ppl.Add(new Person() { Name = boxFirstName.Text, LastName = boxLastName.Text, Age = Int32.Parse(boxAge.Text) });
Then I realized I was using data-binding on my Person Class(INotifyPropertyChanged) with properties so I changed it to :
ppl.Add(new Person() { Name = person.Name, LastName = person.LastName, Age = person.Age});
Thanks again guys for the replies !!
Have a good day !
Question 1:
None, there is no difference. {Binding xyz} is the same as {Binding Path=xyz}, it's almost like a shortcut. But it can only be used on the first thing you write in your binding, for example, you cannot do this:
{Binding ElementName=myElement, xyz}
Instead, you would do this:
{Binding ElementName=myElement, Path=xyz}
Or even better:
{Binding xyz, ElementName=myElement}
Here's a related question.
Question 2:
What you have done is correct, your collection of people should be exposed as a Property, why? Because then you can bind to it.
There is no need for a static property in this scenario.
I would strongly suggest researching the MVVM Design Pattern. You can find a tutorial here
1) Many markup extensions understand shortened syntax, there is no difference between {Binding Persons} and {Binding Path=Persons}. However, sometimes you must use full syntax.
One example would be to make own
public class ExceptionBinding : Binding
{
public ExceptionBinding()
{
ValidationRules.Add(new ExceptionValidationRule());
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
}
}
then you must use full syntax {l:ExceptionBinding Path=Persons}.
2) It depends. You don't have to use ObservableCollection<> if collection is not going to change after you bind to it. Creating List<>, filling it up and then binding to it will work pretty well.
You have to read about MVVM, because using it will simplify usage scenarios and makes many things more clear.
Mike covered what I wanted to say ...
In addition to the binding, you can also show different things in your bindings. Here's a tutorial I've wrote for the code project: Understanding SelectedValue, SelectedValuePath, SelectedItem & DisplayMemberPath + Demo
You can do mockups of your class with dummy data so you'll see a preview in your XAML designer in VS. MVVM light framework helps out and has some cool features as well. There are other frameworks, and you don't really need one for doing MVVM, but they help.
Other than that, I wish you good luck on your journey ... :) once you'll master it, it'll be fun ...
None, there is no difference. {Binding propertyName} is the same as {Binding Path=propertyName}, it's almost like a shortcut, but Constructor get called because of DataContext="{Binding Source={StaticResource people}}".
It depends. You don't have to use ObservableCollection<> if collection is not going to change after you bind to it. Creating List<>, filling it up and then binding to it will work pretty well.But if you want to change collection from screen and update list then you need to go for ObservableCollection<>
I'm having problem with binding Collection do ListView.
public static ObservableCollection<ParagonViewClass> mparagonViewList = new ObservableCollection<ParagonViewClass>();
public ObservableCollection<ParagonViewClass> paragonViewList
{
get
{
return mparagonViewList;
}
}
In method, when user add new item, I'm adding it to list:
paragonViewList.Insert(0, newPar);
Also tried with mparagonViewList.Insert(0, newPar);
Itemssource in xaml file:
<ListView Grid.Row="1" Name="paragonListView1" ItemsSource="{Binding paragonViewList}" .../>
#EDIT: Listview have DataTemplate (Grid with labels - im prettu sure that binding is ok, becouse it works with just simply setting myListVIew.ItemsSource = myLis;)
It looks like when I click on product to add to listview it does insert to database, but I cannot see that product on listview. Probably there's little stupid problem, but I cant really find it ;)
Thanks for any answers!
Looking at the code you supplied, it is hard to figure out what you are doing wrong, if anything. So, I have thrown together a little sample application that works (from the WPF point of view anyway).
My model is called ItemModel, rather than ParagonViewClass, and is defined as follows
public class ItemModel
{
public ItemModel() { }
public string Text { get; set; }
}
My Xaml is
<Window x:Class="StackOverflow._20799346.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:StackOverflow.Common;assembly=StackOverflow.Common"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Button Content="Add Item" Click="AddItem_OnClick" />
</StackPanel>
<ListView ItemsSource="{Binding Path=Items}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type common:ItemModel}">
<TextBlock Text="{Binding Path=Text}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DockPanel>
</Window>
Note the DataContext being bound to RelativeSource Self, allowing the code behind to be used as the ViewModel. I usually prefer to create a separate ViewModel class but this approach has its advantages as one can event directly from a control into the ViewModel, rather than mucking around with commands.
The code behind, now the view model, looks like
public partial class MainWindow : Window
{
private ObservableCollection<ItemModel> items;
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<ItemModel> Items { get { return items ?? (items = new ObservableCollection<ItemModel>()); } }
private void AddItem_OnClick(object sender, RoutedEventArgs e)
{
Items.Add(new ItemModel() { Text = Items.Count.ToString(CultureInfo.CurrentCulture) });
}
}
I have utilised a lazy load technique on the Items property. It will only be instantiated when it is accessed. For simplicity, when the Add Item button is clicked, I am adding a new item with its text set to the count of the Items collection.
You should be able to past this code into a new WPF application project, fix the namespacing in the xaml file and run it.
Now, as hinted at above by Rohit Vats, the Items property does not require a Setter. The ObservableCollection itself notifies the WPF binding subsystem when an item has been added or removed via both the INotifyPropertyChanged and INotifyCollectionChanged interfaces, both of which it implements.
I know this does not directly answer your question but with out further information (ie code) about the original problem, it is not possible to know what is going wrong.
Hopefully the example helps.
NOTE: I have removed exception management for brevity.
I need to create a small GUI application to manually invoke some driver commands.
In total, there are about 40 commands and some of them with additional arguments.
The request is, that all commands should be on a single page. Apart from this, there are no requirements and since it is just a testing environment, the user experience is only a minor concern.
When I start doing it the "regular" way and just add buttons and input elements for the arguments, I end up with a really cluttered UI. It also feels plain wrong to do something like
<Button Command="{Binding DriverCommand} CommandParameter=1/>
For all 40 commands
So my question is, what would be a good way to make lots of commands with varying parameters available?
I would prefer an MVVM way, simply because I want to further learn this pattern.
An implementation where I have my commands (as enums?) in my viewmodel and can just bind it to a control in the view, would be ideal. I could then reuse the UI with different drivers (which is something that is very probable).
Thanks in advance
You could go with something similar to the following:
View-models:
public class CommandDashboardViewModel
{
public ObservableCollection<DriverCommandViewModel> DriverCommands { get; set; }
}
public class DriverCommandViewModel
{
// all of these properties have to implement INPC
public string CommandText { get; set; }
public ICommand Command { get; set; }
public object CommandParameter { get; set; }
}
View:
<!-- the DataContext of this view is instance of CommandDashboardViewModel -->
<ItemsControl ItemsSource="{Binding DriverCommands}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content={Binding CommandText} Command={Binding Command} CommandParameter={Binding CommandParameter}/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've putted it together of the top of my head so my apologies for any syntax errors.