I am trying to bind values to Combobox in a Windows 10 Universal App. I am using MVVM Light. I can bind all values properly except for Combo Box. The items are never shown. I am not sure what I am missing.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BigappleSP.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModels="using:BigappleSP.ViewModels"
x:Class="BigappleSP.Views.ContactusPage"
mc:Ignorable="d" DataContext="{Binding ContactusViewModdel, Source={StaticResource Locator}}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<RelativePanel FlowDirection="LeftToRight" Height="640" VerticalAlignment="Bottom">
<TextBox x:Name="txtName" MinWidth="320"
PlaceholderText="Name" InputScope="PersonalFullName"
RelativePanel.AlignHorizontalCenterWithPanel="True"
Text="{Binding ContactusViewModel.Name, Mode=TwoWay}"
Margin="10,10"/>
<TextBox x:Name="txtEmail" MinWidth="320"
PlaceholderText="Email"
RelativePanel.AlignHorizontalCenterWithPanel="True"
RelativePanel.Below="txtName"
Margin="10,10"
Text="{Binding ContactusViewModel.Email, Mode=TwoWay}"
InputScope="EmailSmtpAddress" />
<TextBox x:Name="txtPhone" MinWidth="320"
PlaceholderText="Phone Number"
RelativePanel.AlignHorizontalCenterWithPanel="True"
RelativePanel.Below="txtEmail" Margin="10,10"
InputScope="TelephoneNumber"
Text="{Binding ContactusViewModel.PhoneNumber, Mode=TwoWay}"/>
<ComboBox x:Name="lstOptions" MinWidth="320" MinHeight="35"
RelativePanel.AlignHorizontalCenterWithPanel="True"
RelativePanel.Below="txtPhone" Margin="10,10"
ItemsSource="{Binding Path=ContactusViewModel.AvailableOptions, Mode=TwoWay}"
PlaceholderText="How can we help you"
IsSynchronizedWithCurrentItem="False"
DisplayMemberPath="Title">
</ComboBox>
<TextBox x:Name="txtMessage" MinWidth="320" MinHeight="150"
RelativePanel.AlignHorizontalCenterWithPanel="True"
RelativePanel.Below="lstOptions"
InputScope="Text" Margin="10,10"
Text="{Binding ContactusViewModel.Message, Mode=TwoWay}"/>
</RelativePanel>
</Grid>
View Model
public class ContactusViewModel : Template10.Mvvm.ViewModelBase
{
public string Name { get; set; }
public string Email { get; set; }
public int PhoneNumber { get; set; }
private ObservableCollection<Options> _options = new ObservableCollection<Models.Options>();
public ObservableCollection<Options> Options
{
get
{
if (_options == null || _options.Count <= 0)
{
_options.Add(new Options() { Id = 1, Title = "Development" });
_options.Add(new Options() { Id = 2, Title = "Training" });
_options.Add(new Options() { Id = 3, Title = "Consulting" });
}
return _options;
}
set
{
_options = value;
}
}
public string Message { get; set; }
// constructor
public ContactusViewModel()
{
_options.Add(new Options() { Id = 1, Title = "Development" });
_options.Add(new Options() { Id = 2, Title = "Training" });
_options.Add(new Options() { Id = 3, Title = "Consulting" });
// Options = _options;
}
public override void OnNavigatedTo(object parameter, NavigationMode mode, IDictionary<string, object> state)
{
base.OnNavigatedTo(parameter, mode, state);
}
}
I am using Options as observable collection to bind to Combo Box.
There is no AvailableOptions property on your view model, there is only Options.
You also need to have another property in the view model for the selected option, and bind it to the combo box's SelectedItem property.
Related
I have been pounding my head on a table today trying to get my drag and drop events to fire. The drag and drop functionality works on the interface, but the events wont fire. I need the events to fire so I can update the database with the new order of the objects. What am I doing wrong?
In the code below, I place break points in the 'Drop' and 'DragOver' methods, but they never get hit.
XAML:
<Window x:Class="Reorder_item_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"
xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop">
<Grid>
<ListBox Grid.Column="1" SelectionMode="Extended" ItemsSource="{Binding MSPCollection}"
dd:DragDrop.IsDragSource="True" Width="300" Margin="0,0,5,0" dd:DragDrop.IsDropTarget="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="#2ba3d5" Height="50" Width="280">
<TextBlock Text="{Binding Name}" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="40"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
c#:
public class MSP {
public int Id { get; set; }
public string Name { get; set; }
}
class MainViewModel : IDropTarget
{
public ObservableCollection<MSP> MSPCollection { get; set; }
public MainViewModel() {
MSPCollection = new ObservableCollection<MSP>();
MSPCollection.Add(new MSP() {
Id = 1,
Name = "Anis Derbel"
});
MSPCollection.Add(new MSP()
{
Id = 2,
Name = "Firas Mdimagh"
});
MSPCollection.Add(new MSP()
{
Id = 3,
Name = "Khaled Jemni"
});
MSPCollection.Add(new MSP()
{
Id = 4,
Name = "Sahbouch"
});
}
public void DragOver(IDropInfo dropInfo) {
if (dropInfo.Data is MSP) {
dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
dropInfo.Effects = DragDropEffects.Move;
}
}
public void Drop(IDropInfo dropInfo) {
MSP msp = (MSP)dropInfo.Data;
((IList)dropInfo.DragInfo.SourceCollection).Remove(msp);
}
}
You also need to set the DropHandler via the respective Attached Property:
<ListBox ItemsSource="{Binding Collection}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}" />
From documentation
I had a research by criteria with Two combobox, it works fine
after the research is finished, I have a button Display All : to reset the combobox to null..and the DataGrid display with all elements ,
The problem that the combobox must be empty when I click on the Button Dispaly All!
Without select an element in combobox(just dispaly the datagrid):I have 6 elements in the datagrid, it is correct..and the combobox are Empty
After select the Search criteria, i have the result correct: (I have just 3 results, it is the correct action)
3 elements picture
When I click on the button Display All:(I have all the elements in datagrid, 6 elements..It is correct) But the Combobox aren't empty!!
6 elements picture
The view:
<Window x:Class="WPFAuthentification.Views.BusinesseventsView"
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" >
<Label Content="Entity Type" Width="128" Grid.Row="1" Grid.ColumnSpan="2"/>
<ComboBox HorizontalAlignment="Center" VerticalAlignment="Center"
ItemsSource="{Binding EntityLevelEnum}"
SelectedItem="{Binding EntityType, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, TargetNullValue=''}"
Grid.ColumnSpan="2" Grid.Column="1" />
<Button Content="Dislplay all" ToolTip="Display All Business Events"
VerticalAlignment="Top" Command="{Binding Initialize}"
Visibility="{Binding Path=ShowDisplayAllButton, Converter={StaticResource BoolToVis}}" />
<DataGrid ..... />
</Window>
The ViewModel:
class BusinesseventsViewModel : ViewModelBase1
{
private ObservableCollection<BusinessEventClass> businessEventsList;
private RelayCommand<string> initialize;
public RelayCommand<string> Initialize
{
get { return initialize; }
}
public BusinesseventsViewModel()
{
//businessEventsList: to Get all the Business events
businessEventsList = new ObservableCollection<BusinessEventClass>(WCFclient.getAllBusinessEvent());
//Enumeration of Entity Type and Criticality
levelCriticalityEnum = new ObservableCollection<Level_Criticality>(Enum.GetValues(typeof(Level_Criticality)).Cast<Level_Criticality>());
entityLevelEnum = new ObservableCollection<BusinessEntityLevel>(Enum.GetValues(typeof(BusinessEntityLevel)).Cast<BusinessEntityLevel>());
//the Button Display All :
initialize = new RelayCommand<string>(initFunc);
}
//Function of the Button Display All
private void initFunc(object obj)
{
EntityType = null;
OnPropertyChanged("EntityLevelEnum");
Criticality = null;
OnPropertyChanged("Criticality");
}
private string entityType;
public string EntityType
{
get { return entityType; }
set
{
entityType = value;
businessEventsList = filterByCriteria(entityType, criticality);
OnPropertyChanged("BusinessEventsList");
OnPropertyChanged("EntityType");
}
}
//Function of the research :
public ObservableCollection<BusinessEventClass> filterByCriteria(string entityType, string criticality)
{
BusinessEventsList = new ObservableCollection<BusinessEventClass>(WCFclient.getAllBusinessEvent());
ObservableCollection<BusinessEventClass> updatedList = new ObservableCollection<BusinessEventClass>();
if ((entityType == null) && (Criticality == null))
{
updatedList = businessEventsList;
}
if ((entityType != null && entityType != "") && (Criticality != null))
{
updatedList = new ObservableCollection<BusinessEventClass>(BusinessEventsList.Where(a => a.EntityType.ToString().ToLower().Equals(criticality.ToString())
&& a.Critciality.ToString().Equals(criticality.ToString())));
}
}
There must be something wrong with your implementation of the INotifyPropertyChanged interface.
Using GalaSoft.MvvmLight I did this, and works without problem;
Window.cs content:
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
}
public class TestViewModel : ViewModelBase
{
private string _selectedItem;
public RelayCommand Command { get; }
public ObservableCollection<string> ItemsSource { get; }
public string SelectedItem
{
get { return _selectedItem; }
set { Set(ref _selectedItem, value); }
}
public TestViewModel()
{
Command = new RelayCommand(() => SelectedItem = null);
ItemsSource = new ObservableCollection<string> { "index 0", "index 1", "index 2", "index 3" };
}
}
and my Window.xaml content
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type testClean:TestViewModel}">
<Grid>
<Viewbox>
<TextBlock Foreground="HotPink">just some pink text</TextBlock>
</Viewbox>
<ComboBox Height="50" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="20" SelectedIndex="0"
ItemsSource="{Binding ItemsSource}"
SelectedItem="{Binding SelectedItem}"/>
<Button Command="{Binding Command}" Height="50" Width="100" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="250,20,20,20">Reset</Button>
</Grid>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<ContentControl Content="{Binding}" />
Tested and working as expected (when you put null as SelectedItem the combobox returns empty)
I cant bind the variable from code behind in my wpf radiobutton
Can anyone help me to display the values from the variables in the content from the radio button.
MainWindow.xaml:
<RadioButton GroupName="Preis" Grid.Row="10" Content="{Binding Name1}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="11" Content="{Binding Name2}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="12" Content="{Binding Name3}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="13" Content="{Binding Name4}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="14" Content="{Binding Name5}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Produkte produkte = new Produkte();
produkte.Name1 = "Handstaubsauger";
produkte.Name2 = "Fensterwascher";
produkte.Name3 = "Dampfreiniger";
produkte.Name4 = "Hochdruckreiniger";
produkte.Name5 = "Geschenkgutschein";
// Regex für Email
String regexEmail = #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
// Hier weitermachen
}
}
Produkte.cs
public class Produkte
{
public String Name1 { get; set; }
public String Name2 { get; set; }
public String Name3 { get; set; }
public String Name4 { get; set; }
public String Name5 { get; set; }
public Int16 Stimmen1;
public Int16 Stimmen2;
public Int16 Stimmen3;
public Int16 Stimmen4;
public Int16 Stimmen5;
}
public MainWindow()
{
InitializeComponent();
Produkte produkte = new Produkte();
produkte.Name1 = "Handstaubsauger";
produkte.Name2 = "Fensterwascher";
produkte.Name3 = "Dampfreiniger";
produkte.Name4 = "Hochdruckreiniger";
produkte.Name5 = "Geschenkgutschein";
// ADD THIS
DataContext = produkte;
// Regex für Email
String regexEmail = #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
// Hier weitermachen
}
Note that if you try to bind to Stimmen1, Stimmen2, etc. in your view, it will fail, because they are fields. They must have { get; } to be able to bind to them.
You really need to turn Produkte into a proper viewmodel with INotifyPropertyChanged etc., but this will get a read-only view working right now.
In your xaml within the Window tag on the top, you would need to define your DataContext. If it is your code behind it would be Self. Once you have the DataContext set, you will be able to access public properties for binding.
<Window x:Class="Account.Client.PotentialMisallocation.Controls.DisplayAndFilter"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
You will need to expose a public property of type Product in your code behind:
public Product Product
{
get { return new Product() {Id = 1, Name = "James"}; }
}
Then in xaml, you would do sth like:
<Label x:Name="label" Content="{Binding Product.Id}" />
<Label x:Name="label1" Content="{Binding Product.Name}" />
I am new to MVVM and WPF, I have the below model which I want to show it to user using the data binding (Code for viewmodel and xaml is also provided below). But I am not sure what is missing, because the list of users are not being shown on UI at all. Can anyone tell me which I am missing from my code?!
If instead Class of Users, I use a List from class User:
private List<User> _UsersList;
public List<User> users
{
get { return _UsersList; }
set { _UsersList = value; }
}
, then the biding works!, but if I use Users class, the binding does not work!
Model:
public class User : ObservableObject
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool IsPremiumUser { get; set; }
public string selectedItem { get; set; }
public string SelectedValue
{
get { return selectedItem; }
set
{
selectedItem = value;
// suser.age = Convert.ToInt32(value);
RaisePropertyChangedEvent("SelectedValue");
}
}
public int[] myItem { get; set; }
public int[] UserItems
{
get { return myItem; }
set { myItem = value; }
}
private SelectedUser suser = new SelectedUser();
public int selected { get; set; }
public int Selected
{
get { return selected; }
set
{
selected = value;
suser.age = Convert.ToInt32(value);
RaisePropertyChangedEvent("Selected");
}
}
}
public class Users : ObservableObject
{
private List<User> mylist = new List<User>();
private List<User> list
{
get { return mylist; }
set
{
mylist = value;
}
}
public void Add(User user)
{
this.list.Add(user);
}
public User GetById(int id)
{
return this.list.First(u => u.ID == id);
}
}
ViewModel:
public class ViewModel : ObservableObject
{
public ViewModel()
{
users = new Users();
for (int i = 0; i < 100000; ++i)
{
int[] numbers;
numbers = new int[3] { 1, 2, 3 };
var user = new User { ID = i, Name = "Name " + i.ToString(), Age = 20 + i, UserItems = numbers, SelectedValue = "0" };
if (i == 2 || i == 4)
{
user.IsPremiumUser = true;
}
users.Add(user);
}
}
private Users _UsersList;
public Users users
{
get { return _UsersList; }
set { _UsersList = value; }
}
private int _currenuser;
public int CurrentUser
{
get
{
return _currenuser;
}
set
{
_currenuser = value;
RaisePropertyChangedEvent("CurrentUser");
}
}
}
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Icon="C:\Users\maninx2\Documents\Visual Studio 2013\Projects\SampleFormMaker1\WpfApplication1\abbott_point_of_care_HuT_icon.ico"
Title="MainWindow" Height="700" Width="1249.129">
<Window.Resources>
<DataTemplate x:Key="NormalUserDataTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBox Text="{Binding SelectedValue, UpdateSourceTrigger=PropertyChanged}" Width="300" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="PremiumUserDataTemplate">
<StackPanel Background="LightBlue">
<ComboBox SelectedIndex="{Binding SelectedValue, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Name}" Width="300" ItemsSource="{Binding UserItems}"/>
</StackPanel>
</DataTemplate>
<local:PremiumUserDataTemplateSelector x:Key="myPremiumUserDataTemplateSelector" />
</Window.Resources>
<TabControl Name="TabControl1">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="General">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Height="800" Orientation="Horizontal" >
<ListView x:Name="myListView" ItemsSource="{Binding users, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemTemplateSelector="{StaticResource myPremiumUserDataTemplateSelector}" SelectedIndex="{Binding CurrentUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ListView>
<ListView x:Name="myListView1" ItemsSource="{Binding users, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" >
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Selected Values"
DisplayMemberBinding="{Binding SelectedValue}" />
</GridView>
</ListView.View>
</ListView>
<Button Content="Next"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="75"
Click="Button_Click"/>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem Header="Second Tab">
<StackPanel>
<TextBlock Name="lbl1" Text="{Binding CurrentUser, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Previous"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top"
Width="75"
Click="Button_Click1"/>
</StackPanel>
</TabItem>
</TabControl>
</Window>
You are missing inheriting the Users from ObservableCollection. So, WPF engine does not know how to get the data from this class.
Update:
#user3033921: You inherited it from ObservableObject not ObservableCollection. So, the thing is if you want this class to be recognized from as a list then you would have to get that class inherited by an ICollection object and if you want that class to be observable it should be implementing both ICollection and INotifyPropertyChange. So, to #BradleyDotNet's point if you dont have any specific reason to create your own type, then just create a object of users with type ObservableCollection. If you have a specific need to have a type Users then you can derive it from ObserableCollection as recommended solution. But keep in mind you do not want to have List in the Users class anymore as your class is now by itself is a list. So, if you have any specific implementation to do like GetByID, then the class would look like:
public class Users :ObservableCollection<User>
{
public User GetById(int id)
{
return this.First(u => u.ID == id);
}
}
Please have a look at this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{StaticResource vm}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="194*"/>
<ColumnDefinition Width="489*"/>
</Grid.ColumnDefinitions>
<ListView HorizontalAlignment="Left"
ItemsSource="{Binding Path=Places}"
SelectedItem="{Binding Path=SelectedPlace, Mode=TwoWay}" Margin="0,96,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Title}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Grid.Column="0" HorizontalAlignment="Left">
<TextBlock
VerticalAlignment="Top"
Text="{Binding SelectedPlace.Title}" Margin="0,64,0,0"/>
</StackPanel>
</Grid>
I am passing in list of Places, its working fine and the list gets displayed in the view. The problem is the selectedItem. The intellisense finds the property here
Text="{Binding SelectedPlace.Title}"
But it does not show up in the view.
When I put a breakpoint in my viewmodel, I can see that that value changes:
public class MainViewModel : ViewModelBase
{
public ObservableCollection<Place> Places { get; set; }
public Place _selectedPlace { get; set; }
public Place SelectedPlace
{
get { return _selectedPlace; }
set { _selectedPlace = value; }
}
public MainViewModel()
{
Places = new ObservableCollection<Place>()
{
new Place() {Title = "London", Description = "London is a nice..."},
new Place() {Title = "Dublin", Description = "Dublin is a ...."}
};
}
}
Does anyone know what i am missing? Thanks
You need to invoke RaisePropertyChanged.
public Place SelectedPlace
{
get { return _selectedPlace; }
set
{ _selectedPlace = value;
RaisePropertyChanged("SelectedPlace")}
}
}
And you should probably also initialize this property:
public MainViewModel()
{
Places = new ObservableCollection<Place>()
{
new Place() {Title = "London", Description = "London is a nice..."},
new Place() {Title = "Dublin", Description = "Dublin is a ...."}
};
SelectedPlace = Places[0];
}
And do yourself a favor by making the backing field of the SelectedPlace property a private field. You probably want to change it as this:
public Place _selectedPlace { get; set; }
to
private Place _selectedPlace;