How to bind imported ObservableCollection of strings to ItemsControl - c#

example
class abc
{
public ObservableCollection<string> Data { get; set; }
//data will be initialized in some functions
}
and wpf application
namespace WpfApplication
{
public partial class MainWindow : Window
{
[Import(typeof(GateManager))]
public abc _abc { get; set; }
public MainWindow()
{
InitializeComponent();
}
}
public void OnImportsSatisfied()
{
var binding = new Binding
{
Source = _abc,
Path = new PropertyPath("Data")
};
databox.SetBinding(ItemsControl.SourceProperty, binding);
//databox is name of the ItemControl like //<ItemsControl x:Name="databox" ScrollViewer.VerticalScrollBarVisibility="Auto">
// <ItemsControl.ItemTemplate>
// <DataTemplate>
// <StackPanel Orientation="Horizontal">
// <TextBlock Text="{Binding}" />
// </StackPanel>
// </DataTemplate>
//</ItemsControl.ItemTemplate>
//</ItemsControl> }
}
}
Im trying to do like this but this is not working

Add DataContext also
<Window.DataContext>
<ViewModel:ManageUserViewModel/>
</Window.DataContext>
in cs file :
private ObservableCollection<UserType> _listUserTypes = new ObservableCollection<UserType>();
public ObservableCollection<UserType> UserTypes
{
set
{
_listUserTypes = value;
}
get
{
return _listUserTypes;
}
}
In Xaml:
<ItemsControl ItemsSource="{Binding Path=UserTypes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

public List<string> Data { get; set; }
in XAML,
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You want to set the ItemSource to the instance of an ObservableCollection you created in the constructor:
YourItemsControL.ItemsSource = Data ;

Related

How can I fill a listbox like this with data

What's the c# code to fill these listbox with datas (strings)
I saw this on https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/data-templating-overview
but there's no C# Code.
I want to have a listbox like in "Defining a Simple DataTemplate" on the link
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/data-templating-overview
Picture from listbox [1]: https://i.stack.imgur.com/K4HZS.png
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
To do this, you will need to learn about MVVM pattern.
First, you need a class TODO in the model with properties for TaskName, Description and Priority.
public class Todo
{
public string TaskName { get; set; }
public string Description { get; set; }
public int Priority { get; set; }
}
Then, you will need a class to store the collection of TODO, your "myTodoList" in the xaml :
public class TodoViewModel
{
public ObservableCollection<Todo> TodoList { get; } = new ObservableCollection<Todo>();
public TodoViewModel()
{
TodoList.Add(new Todo { TaskName = "Todo1", Description = "Todo 1 Description", Priority = 1 });
TodoList.Add(new Todo { TaskName = "Todo2", Description = "Todo 2 Description", Priority = 2 });
}
}
Then, you will need to set the datacontext in the code behind of the xaml :
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new TodoViewModel();
InitializeComponent();
}
}
Finally, here is your XAML (I changed it a bit, you don't need things like "Path=") :
<ListBox Width="400" Margin="10" ItemsSource="{Binding TodoList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding TaskName}" />
<TextBlock Text="{Binding Description}"/>
<TextBlock Text="{Binding Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And it should work well :)
You should have something like this.
MainWindow.xaml.cs:
public List<ToDo> ToDoList {get; set;}
public MainWindow()
{
InitializeComponent();
DataContext=this;
ToDoList= new List<ToDo>()
{
new ToDo{TaskName="Task1",Description="First Task"},
new ToDo{TaskName="Task2",Description="Second Task"}
};
}
ToDo.cs:
public class ToDo
{
public string TaskName {get; set;}
public string Description {get; set;}
}
Modify your Binding expression to:
<ListBox Width="400" Margin="10"
ItemsSource="{Binding ToDoList}">

ObservableCollection binding does not work as expected [duplicate]

This question already has answers here:
Why does WPF support binding to properties of an object, but not fields?
(2 answers)
Closed 4 years ago.
I have a problem with binding ObservableCollections. Other properties (string) are OK. Here is my code:
MainWindow.xaml
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<ItemsControl ItemsSource="{Binding Data}">
<TextBlock Text="{Binding B}"/>
</ItemsControl>
</StackPanel>
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowVm();
}
MainWindowVm
class MainWindowVm
{
public ObservableCollection<A> Data;
public string Title { get; set; } = "HELLO WORLD";
public MainWindowVm()
{
Data = new ObservableCollection<A>() {new A() {B = "X"}, new A() {B = "X"}};
}
}
class A
{
public string B { get; set; }
}
Result
What am I doing wrong?
OK, as others already mentioned, you need to change the Data field into a property.
public ObservableCollection<A> Data { get; set; }
To get rid of the error
Items collection must be empty before using ItemsSource.
Change your XAML to:
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding B}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>

Dynamically Create Controls in MVVM

I am pretty new to WPF. I am trying to create controls dynamically in MVVM but controls are not rendered on view. I want some number of label and textbox to be created on view.
Below is my code:
Model Code
public class MyModel
{
public string KeyName
{
get;
set;
}
public string KeyValue
{
get;
set;
}
}
ModelView Code
public class MyViewModel
{
private ObservableCollection<MyModel> propertiesList = new ObservableCollection<MyModel>();
public CustomWriterViewModel()
{
GetMyProperties()
}
public ObservableCollection<MyModel> Properties
{
get { return propertiesList; }
}
private void GetMyProperties()
{
MyModel m = new MyModel();
m.KeyName = "Test Key";
m.KeyValue = "Test Value";
MyModel.Add(m);
}
}
View Code(Which is user control)
<Grid>
<ItemsControl ItemsSource="{Binding Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type cw:MyModel}">
<StackPanel Orientation="Horizontal">
<Label Margin="10" Content="{Binding Properties.KeyName}"></Label>
<TextBox Margin="10" Text="{Binding Properties.KeyValue}" Width="250"></TextBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
When view renders, I can only see empty textbox. I cannot understand what is wrong..?
As per my comment:
The DataTemplate receives an individual item as its DataContext, therefore you only need to include item level property names within your binding paths like:
<DataTemplate DataType="{x:Type cw:MyModel}">
<StackPanel Orientation="Horizontal">
<Label Margin="10" Content="{Binding KeyName}"></Label>
<TextBox Margin="10" Text="{Binding KeyValue}" Width="250"></TextBox>
</StackPanel>
</DataTemplate>

How generate(binding) quiz in form using wpf mvvm

How binding quiz with different type questions in WPF app using MVVM?
QuizPageViewModel:
public class QuizPageViewModel : ViewModelBase
{
public QuizPageViewModel()
{
QuizCollection = new ObservableCollection<QuizQuestion>();
}
public ObservableCollection<QuizQuestion> QuizCollection { get; set; }}
Where QuizQuestion: - EF Entity
public partial class QuizQuestion
{
public QuizQuestion()
{
QuizAnswers = new HashSet<QuizAnswer>();
QuizMultiQuestions = new HashSet<QuizMultiQuestion>();
}
public long Id { get; set; }
public int QuizId { get; set; }
***public String Type { get; set; }***
[Required]
public string Name { get; set; }
}
Question Type can be truefalse, multianswer, multichoice and other type
in xaml:
<ItemsControl ItemsSource="{Binding QuizCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Path=QuizAnswers}"
VerticalAlignment="Stretch"
Background="Transparent">
<ListBox.ItemTemplate>
<ItemContainerTemplate>
<RadioButton GroupName="{Binding Id}"
Content="{Binding Name}" />
</ItemContainerTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
this xaml code display only radiobutton question of quiz. How binding and display other Type of question (checkbox, combobox, textbox)? HELP)))
You can use an Item template selector in your items control to display different controls/templates depending on the question.
In the code below you can see that there's a conditional statement that checks the type of question and return a template based on the type of question.
public class QuiztemplateSelector : DataTemplateSelector
{
public DataTemplate TrueOrFalseTemplate { get; set; }
public DataTemplate MultiAnswerTemplate { get; set; }
public DataTemplate MultiChoiceTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var question = item as QuizQuestion;
if (question.Type.Equals("TruOrFalse"))
return TrueOrFalseTemplate;
else if (question.Type.Equals("MultiAnswer"))
return MultiAnswerTemplate;
else if ("MultiChoice")
return MultiChoiceTemplate;
return null; //Or your default Template.
}
}
Now in your xaml, you can create templates for the types of questions (i.e. true/False, Multi choice, multi answer). Then you need to pass those templates to the QuiztemplateSelector as shown below.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<DataTemplate x:Key="TrueOrFalse">
<!-- Write your True or false template here-->
</DataTemplate>
<DataTemplate x:Key="MultiChoice">
<!-- Write your MultiChoice template here-->
</DataTemplate>
<DataTemplate x:Key="MultiAnswer">
<!-- Write your multianswer Template here -->
</DataTemplate>
<local:QuizTemplateSelector x:Key="QuizTemplateSelector"
MultiAnswerTemplate="{StaticResource MultiAnswer}"
TrueOrFalseTemplate="{StaticResource TrueOrFalse}"
MultiChoiceTemplate="{StaticResource MultiChoice}" />
</Grid.Resources>
<ItemsControl ItemsSource="{Binding QuizCollection}" ItemTemplateSelector="{StaticResource QuiztemplateSelector}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Path=QuizAnswers}"
VerticalAlignment="Stretch"
Background="Transparent">
<ListBox.ItemTemplate>
<ItemContainerTemplate>
<RadioButton GroupName="{Binding Id}"
Content="{Binding Name}" />
</ItemContainerTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
You can read more abour DataTemplateSelector here.

Binding isn't working for ListBox while using MVVM

I have a simple UserControl with a DropDown showing versions like V14, V15 etc.
I have another ListBox whose ItemSource is binded to a property in the ViewModel which depend upon the SelectedValue of the Version DropDown.
ViewModel Looks like this:
class MultiSelectEnvironmentContextControlViewModel: ViewModelBase
{
private string selectedVersion;
private DomainFacade domainFacade;
private ObservableCollection<string> environments= new ObservableCollection<string>();
public MultiSelectEnvironmentContextControlViewModel()
{
domainFacade = ((App) Application.Current).DomainFacade;
}
public IEnumerable<string> EnvironmentVersions
{
get
{
return (domainFacade.GetEnvironmentVersions().Select(v => "Version " + v));
}
}
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
RaisePropertyChanged("Environments");
}
}
public ObservableCollection<string> Environments
{
get
{
environments = (ObservableCollection<string>)(domainFacade.GetEnvironments(SelectedVersion));
return environments;
}
}
}
I am keeping track of the SelectedVersion in a property which raises PropertyChanged on Environments so that whenever SeelectedVersion changes, the Environments should update the UI.
Issue I am facing is, ehn I run the application, I see the versions being populated, but there is nothing in the ListBox.
I am setting the DataContext of the UserControl to the ViewModel in the constructor of the UserControl.
Here is how my Control.cs file looks like:
public partial class MultiSelectEnvironmentContextControl : UserControl
{
private static MultiSelectEnvironmentContextControlViewModel dataContext = new MultiSelectEnvironmentContextControlViewModel();
public MultiSelectEnvironmentContextControl()
{
InitializeComponent();
this.DataContext = dataContext;
dataContext.SelectedVersion = (string)this.ComboBoxVersions.SelectedItem;
}
private void ComboBoxVersions_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
dataContext.SelectedVersion = ((ComboBox) sender).SelectedValue.ToString();
}
}
Here is the XAML:
<ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions" SelectedIndex="0" Margin="10" SelectionChanged="ComboBoxVersions_OnSelectionChanged" ItemsSource="{Binding EnvironmentVersions}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" Margin="10">
<TextBlock VerticalAlignment="Center" Margin="0,0,10,0">Tests to be run for:</TextBlock>
<ComboBox Name="ComboBoxFileTypeSelector" ItemsSource="{Binding AvailableValidationTypes}" DisplayMemberPath="Key" SelectedValuePath="Value" SelectedIndex="0">
</ComboBox>
</StackPanel>
<ListBox x:Name="ListBoxEnvironments" Grid.Column="0" Grid.Row="1" Height="300" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="10" SelectionMode="Multiple" ItemsSource="{Binding Environments}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="800" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="CheckBoxEnvironment" Content="{Binding}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Margin="5">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I believe this is because SelectedVersion has values like "Version 1", "Version 2", etc, but your method DomainFacade.GetEnvironments(string version) expects values like "1", "2" etc.
I would write your viewmodel like this:
public class MultiSelectEnvironmentContextControlViewModel : ViewModelBase
{
private string selectedVersion;
private DomainFacade domainFacade;
private IEnumerable<string> environments;
public MultiSelectEnvironmentContextControlViewModel()
{
domainFacade = ((App)Application.Current).DomainFacade;
EnvironmentVersions = domainFacade.GetEnvironmentVersions();
}
public IEnumerable<string> EnvironmentVersions { get; private set; }
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
RaisePropertyChanged("SelectedVersion");
Environments = domainFacade.GetEnvironments(SelectedVersion);
}
}
public IEnumerable<string> Environments
{
get { return environments; }
set
{
environments = value;
RaisePropertyChanged("Environments");
}
}
}
}
and applied to formatting of environment versions in view:
<ComboBox SelectedItem="{Binding SelectedVersion}"
ItemsSource="{Binding EnvironmentVersions}"
ItemStringFormat="Version: {0}" />

Categories

Resources