adding a list to itemsource, WPF - c#

I am starting with WPF and I have this problem. I have a file called MainWindow.xaml with this code:
<Window x:Class="View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:View" xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid >
<ItemsControl ItemsSource="{Binding}" x:Name="boardView">
</ItemsControl>
</Grid>
</Window>
And I have another file called MainWindow.xaml.cs with this code
namespace ViewModel
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new List<string> { "a", "b", "c", "d", "e" };
}
}
}
Now I have to assign this list to boardView.ItemsSource. How can I do that?

You have four problems here that I can see that would need to get fixed for this to work.
In order for data binding to work, you need to set the DataContext of your MainWindow.
MainWindow.xaml.cs:
// Put this in the constructor after InitializeComponents();
this.DataContext = this;
Another requirement for data binding is to implement the INotifyPropertyChanged interface on the class you wish to having data binding (in your case this is MainWindow, but I recommend you read on MVVM design):
MainWindow.xaml.cs:
public partial class MainWindow : Window, INotifyPropertyChanged
Data bindings only work on public properties, so using var items isn't following this requirement. Instead, make var items a public property that updates itself with the PropertyChanged event whenever the value changes.
MainWindow.xaml.cs:
private List<string> items;
public List<string> Items
{
get => this.items;
set
{
this.items = value;
PropertyChanged?.Invoke(this, new PropertyName(nameof(Items)));
}
}
Lastly, you need to fix your binding in the xaml to bind to your public property.
MainWindow.xaml:
<ItemsControl ItemsSource="{Binding Items}" x:Name="boardView">

Related

Binding Collection in wpf comboBox with mvvm (C#)

I am trying to using mvvm pattern with wpf to create an interface for a project previously did in win form.
In this project i have an object that contains some List<> that i have to show in real time on my interface with a combobox, the problem is that combobox don't change his values. I'm using the dll of mvvm fundation for implement NotifyPropertyChanged. I think to make some mistake but i don'y know where is it.
I've tried to do a simple code with only one list in viewmodel and without a model but the result doesn't change.
<Window x:Class="ProvaComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ProvaComboBox"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.DataContext>
<local:ViewModel />
</Grid.DataContext>
<Button Content="Generate" Command="{Binding Generate}"/>
<Button Content="Clear" Command="{Binding Clear}"/>
<ComboBox ItemsSource="{Binding Path=Word, Mode=OneWay}" />
</Grid>
</Window>
//view Model
class ViewModel:ObservableObject
{
private List<string> _word;
public List<string> Word
{
get { return _word; }
}
public ViewModel()
{
_word = new List<string>();
}
public ICommand Generate
{ get { return new RelayCommand(GenerateExecute); } }
void GenerateExecute()
{
_prova.Add("pippo");
_prova.Add("pluto");
RaisePropertyChanged("Word");
}
public ICommand Clear
{ get { return new RelayCommand(ClearExecute); } }
void ClearExecute()
{
_prova.Clear();
RaisePropertyChanged("Word");
}
}
//View:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
I think that the problem it's RaisePropertyChanged, but it work correctly with normal variables.
I've tryed also using ObservableCollection and it work, but i can't use it with real project.
(p.s. Its my first question in stack overflow, sorry if i did some mistake!)
use ObservableCollection like that
public ObservableCollection<string> Word
{
get => _word;
set
{
_word= value;
RaisePropertyChanged("Word");
}
}
and change the binding mode in your combobox xaml code from OneWay to TwoWay or just remove it to be something like
<ComboBox ItemsSource="{Binding Path=Word}" />

Cascaded command bindings possible

I have a MainWindow that contains multiple views using MVVM. In fact the MainWindow holds only a list of Models and each time a Model is added it creates a View (here a UserControl) and associates the DataContext (Model) to the View. Each view is put into a separate TabItem in a TabControl.
The Model itself has a CommandBindingsCollection and assigns this command bindings to the View. This means that for example F10 is available multiple times, but should only the active View should react on F10.
But, F10 does not work at all. Only if I assign the CommandBinding to the MainWindow it works, but this makes the View dependent on the UserControl and this is not what I want, since I wnat to create the View as independent as possible from the MainWindow.
The only solution I have is to make this dynamically intercepting the change of the current TabItem and add/remove the commands for the active View. Currently everything works without code, but then I have to write code for it.
Attached is a code of the MainWindow:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
</Window>
using System.Windows;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PluginControl aControl = new PluginControl();
Content = aControl;
}
}
}
and the code of the UserControl:
<UserControl x:Class="WpfApplication3.PluginControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Background="White">
<StackPanel>
<Button Command="{Binding myCommand}" Content="PushMe" Focusable="False"/>
<Label Content="Nothing pressed" Name="myLabel"/>
</StackPanel>
</UserControl>
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for PluginControl.xaml
/// </summary>
public partial class PluginControl : UserControl
{
public RoutedCommand myCommand
{
get;
private set;
}
public PluginControl()
{
InitializeComponent();
DataContext = this;
myCommand = new RoutedCommand();
myCommand.InputGestures.Add(new KeyGesture(Key.F10));
CommandBindings.Add(new CommandBinding(myCommand, myCommandHandler));
}
private void myCommandHandler(object sender, ExecutedRoutedEventArgs executed)
{
myLabel.Content = DateTime.Now.ToString();
}
}
}
As you see I have set the Button to Focusable false, since I want to have the command working in general, not only when the button is focused. I'm I missing something or thinking in a wrong direction, that making adding a CommandBinding does not implicitly mean that the command does work without binding it?
Adding the Command to the MainWindow itself works.
Any help?

WPF ComboBox does not display content

I have a simple combo box on my xaml file:
<ComboBox Name="environmentComboBox" Grid.Column="1" Grid.Row="0" Margin="2"
SelectionChanged="environmentComboBox_SelectionChanged"
ItemsSource="{Binding Path=Test}"/>
Here is the code for its content:
private List<string> test = new List<string>(){"1", "2"};
public List<string> Test
{
get
{
return test;
}
set
{
test = value;
}
}
I tried to debug the application, the ComboBox does not show anything.
But when I checked if Test has content, it shows the two strings.
Have to set the views DataContext to the Model/Window containing the List<T>?
If not you need to tell the View what DataContext to use, below is a quick example of a WPF window, and setting the xamls DataContext to the code behind of the View.
Also its recommended to use ObservableCollection<T> when binding collections as adding and removing items will update the ComboBox automatically
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this; // set datacontext
}
private ObservableCollection<string> test = new ObservableCollection<string>() { "1", "2" };
public ObservableCollection<string> Test
{
get { return test; }
set { test = value; }
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ComboBox ItemsSource="{Binding Path=Test}"/>
</StackPanel>
</Window>

How will i show the first item of an observablecollection in a Listbox?

i have this declaration:
public ObservableCollection<SomeType> Collection { get; set; }
i tried something, like:
myListBox.ItemsSource = Collection[0];
to show the first item of Collection in the Listbox control, but it gives error.
how will i do this? what change should i make on the right side?
You need to bind the ItemSource to your collection, and then set the selected index to the one you want (0 in your case)
Here's the smallest example. XAML:
<Window x:Class="WPFSOTETS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<ComboBox ItemsSource="{Binding Collection}" SelectedIndex="2"></ComboBox>
</Grid>
</Window>
Code behind:
using System.Collections.ObjectModel;
using System.Windows;
namespace WPFSOTETS
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<string> Collection
{
get
{
return new ObservableCollection<string> {"one","two","three"};
}
}
}
}
I set the index to 2, just for fun, but you can play with it.
As of comment, if you want to set this in the codebehind, you'll have to name your control, and then you can use it from your codebehind and do your binding and setting there. You can have a look at this answer for example.

WPF Does not show data inside datagrid

I'm following some example from and I cannot display data inside my datagrid. Worth to mention is that I'm getting data from db when looking inside debuger.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
using (session...)
{
using (transaction...)
{
var properties = new List<MyProperty>();
// this variable is populated inside debugger
properties = session.Query<MyProperty>().ToList();
if (properties != null)
{
MRDataGrid.Columns[0].Visibility = System.Windows.Visibility.Hidden;
MRDataGrid.Columns[1].Visibility = System.Windows.Visibility.Hidden;
MRDataGrid.Columns[8].Visibility = System.Windows.Visibility.Hidden;
}
}
}
}
}
MainWindow.xaml
<Window x:Class="MyProject.WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
WindowStartupLocation="CenterScreen" BorderBrush="Black"
Background="AntiqueWhite" ResizeMode="NoResize"
Loaded="Window_Loaded">
<Grid>
<DataGrid AutoGenerateColumns="False" Height="202" HorizontalAlignment="Left" Margin="22,82,0,0"
Name="MRDataGrid" VerticalAlignment="Top" Width="461" ItemsSource="{Binding}"/>
</Grid>
</Window>
Update
I've changed to AutoGenerateColumns="True" in MainWindow.xaml
Added MRDataGrid.ItemsSource = properties; in xaml.cs code
What should I put inside ItemSource in MainWindow.xaml ?
You're not setting any context for ItemsSource="{Binding}" to work with.
Do something like myDataGrid.DataContext=... or bind the data context or change the {Binding} to point where you need it
Such as:
if (properties != null)
{
myDataGrid.ItemsSource = properties;
...
Your datagrid doesn't have columns. You either need to declare them yourself or set AutoGenerateColumns="True" You also need to assign the item source like Sten Petrov said
properties = session.Query().ToList();
MRDataGrid.ItemsSource = properties;

Categories