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>
Related
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">
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}" />
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.
I am new to MVVM and WPF but I know what's going on in MVVM. I have a problem with switching between user controls in mainwindow. In my app I have:
MainWindow.xaml with log and 2 links: Show all and Create new. Of course I have ViewModel for it. I have 2 more UserControls: ShowAll and Create with ViewModels and all logic in it (adding data etc). How can I show create form when I click link Create new or show all when I click ShowAll?
In windowForms I just hide UC, buto here is no code behind :)
My MainWindow.xaml:
<Window x:Class="Test.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="300">
<Grid>
<StackPanel>
<TextBox Text="{Binding Name}"/>
<Button Content="Change" Command="{Binding ChangeCommand}"/>
</StackPanel>
</Grid>
</Window>
My MainWindowViewModel:
class MainWindowViewModel : BaseViewModel
{
private Person _person;
private BaseCommand _changeCommand;
public MainWindowViewModel()
{
_person = new Person();
}
public string Name
{
get
{
return _person.Name;
}
set
{
if (_person.Name != value)
_person.Name = value;
OnPropertyChanged(() => Name);
}
}
public ICommand ChangeCommand
{
get
{
if (_changeCommand == null)
_changeCommand = new BaseCommand(() => change());
return _changeCommand;
}
}
private void change()
{
_person = new Person();
Name = _person.Imie;
}
}
In Create and ShowAll there is no code. In xaml only a label, VM is empty. Just for test.
Thank's for help!
You can use a ContentControl to display a specific DataTemplate based on the type of ViewModel that is bound to the ContentControl.
http://www.japf.fr/2009/03/thinking-with-mvvm-data-templates-contentcontrol/
The command that is bound to the ShowAll button can simply change a property on your main ViewModel which is what is bound to your content control.
I got combobox that contain names. My goal is to search with textbox for a string and than the names that start with this string will display in the combobox.
for example:
my combobox contain the next items:
"Mark" , "Arik", "Michael"
when a user will write "Mi" in the textbox, the combobox will display only "Michael".
P.S there is no button. only textbox and combobox.
I prepared you example.
In my example I use two additional assemblies:
Microsoft.Practices.Prism
System.Windows.Interactivity
XAML file:
<Window x:Class="ComboBoxFilter.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"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
>
<Grid>
<StackPanel>
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding SearchItems}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<ComboBox ItemsSource="{Binding MySourceData}" />
</StackPanel>
</Grid>
</Window>
ViewModel class:
class MainViewModel : NotificationObject
{
public MainViewModel()
{
_myItems.Add("aaa");
_myItems.Add("abb");
_myItems.Add("aab");
_myItems.Add("bbb");
_myItems.Add("bcc");
_myItems.Add("bbc");
SearchItems = new DelegateCommand(this.OnSearchItems);
}
private string _searchText;
public string SearchText
{
get { return _searchText; }
set { _searchText = value; RaisePropertyChanged(() => SearchText); }
}
private ICollectionView _mySourceData;
public ICollectionView MySourceData
{
get { return CollectionViewSource.GetDefaultView(_myItems); }
}
private List<string> _myItems = new List<string>();
public ICommand SearchItems { get; private set; }
private void OnSearchItems()
{
MySourceData.Filter = (o) => { return string.IsNullOrEmpty(SearchText) ? true : (o as string).StartsWith(SearchText); };
}
}
Do not forget set window DataContext in ctor:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
Here is all solution with additional assemblies (ComboBoxFilter.zip).
Well, if you use binding to populate the combobox you should just create text property and bind it to the textbox (two way mode binding).
In the setter of this property you just change the filtering condition of the earlier setup filtering for the view.
http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource.getdefaultview.aspx
And in some cases you may wish to filter the collection not its view.
But it's you who decides.