I am using Itemscontrol with wrappanel being used as ItempanelTemplate. The ItemTemplate using datatemplate containg of combobox.
The combobox contains list of items and when "custom" option is choosen I need to change the combobox control to show start date and end date fields to choose date from calender. The other comboboxes should remain intact.
MainWindow.xaml
<Window x:Class="ICExample.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:ICExample" xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding TimeFrame}" Margin="0,0,5,5" Width="90" Height="60" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
MainWindox.xaml.cs
public partial class MainWindow : Window
{
List<Person> personList = new List<Person>();
public MainWindow()
{
InitializeComponent();
Populate();
DataContext = this.personList;
}
private void Populate()
{
personList.Add(new Person() { TimeFrame = { "1 month", "1 day", "1 year", "custom" } });
personList.Add(new Person() { TimeFrame = { "1 month", "1 day", "1 year", "custom" } });
personList.Add(new Person() { TimeFrame = { "1 month", "1 day", "1 year", "custom" } });
personList.Add(new Person() { TimeFrame = { "1 month", "1 day", "1 year", "custom" } });
}
}
public class Person
{
private List<string> _timeFrame = new List<string>();
public List<string> TimeFrame
{
get
{
return _timeFrame;
}
set
{
_timeFrame = value;
}
}
}
Related
I have a select list called Printers which is filled by default, after selecting a value from this select list the list called Trays should be filled but it doesn't. I've tried various methods but it seems to me that I still don't understand what the problem is. In addition, I would like to see a new list after pressing the Add next row button and it would also be full. I tried to use DependencyProperty and INotifyPropertyChanged but I don't think I fully understand the basics of the assumption or my problem is specific.
<UserControl x:Class="TestWPF.User_Controls.TrayItem"
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:TestWPF.User_Controls"
mc:Ignorable="d"
Name="ucTray"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="White">
<StackPanel Margin="10" x:Name="spTray" Orientation ="Horizontal" Height="35" HorizontalAlignment="Center">
<Label VerticalAlignment="Center">Trays</Label>
<ComboBox Width="250" VerticalContentAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementName=ucTray, Path=Trays }" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label VerticalAlignment="Center">Documents</Label>
<ComboBox Width="250" VerticalContentAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Documents , RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
namespace TestWPF.User_Controls
{
public partial class TrayItem : UserControl
{
public List<string> Trays
{
get { return (List<string>)GetValue(TraysProperty); }
set { SetValue(TraysProperty, value); }
}
// Using a DependencyProperty as the backing store for Trays. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TraysProperty =
DependencyProperty.Register("Trays", typeof(List<string>), typeof(TrayItem), new PropertyMetadata(null));
public List<string> Documents
{
get { return (List<string>)GetValue(DocumentsProperty); }
set { SetValue(DocumentsProperty, value); }
}
// Using a DependencyProperty as the backing store for Documents. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DocumentsProperty =
DependencyProperty.Register("Documents", typeof(List<string>), typeof(TrayItem), new PropertyMetadata(null));
public TrayItem()
{
InitializeComponent();
}
}
}
<Window x:Class="TestWPF.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:TestWPF"
xmlns:control="clr-namespace:TestWPF.User_Controls"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel Margin="10" x:Name="spItems">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Label>Printers</Label>
<ComboBox x:Name="cmbPrinterList" Width="300" SelectionChanged="cmbPrinterList_SelectionChanged" ItemsSource="{Binding MyPrinters}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<control:TrayItem x:Name="cTray" Trays="{Binding MyTrays, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Documents="{Binding Path = MyDocuments, Mode=TwoWay}">
</control:TrayItem>
</StackPanel>
<Button x:Name="btnAddTray" Margin="10" Width="100" Height="40" Click="btnAddTray_Click" >Add next row</Button>
</Grid>
</Window>
namespace TestWPF
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public List<string> MyPrinters { get; set; }
public string? _SelectedPrinter;
public string? SelectedPrinter
{
get
{
return _SelectedPrinter;
}
set
{
_SelectedPrinter = value;
}
}
private List<string>? _MyTrays;
public List<string>? MyTrays
{
get
{
return _MyTrays;
}
set
{
_MyTrays = value;
RaisePropertyChanged("SelectedPrinter");
RaisePropertyChanged("MyTrays");
RaisePropertyChanged("MyDocuments");
}
}
public List<string>? MyDocuments { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyPrinters = new List<string>()
{
"Printer_1",
"Printer_2",
"Printer_3"
};
}
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void cmbPrinterList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string? value = (string?)cmbPrinterList.SelectedItem;
switch (value)
{
case "Printer_1":
MyTrays = new List<string>()
{
"aaa",
"bbb",
"ccc"
};
MyDocuments = new List<string>()
{
"zzz",
"qqq",
"rrr"
};
break;
case "Printer_2":
MyTrays = new List<string>()
{
"111",
"222",
"333"
};
MyDocuments = new List<string>()
{
"666",
"777",
"888"
};
break;
case "Printer_3":
MyTrays = new List<string>()
{
"1dg",
"b2f",
"bs4"
};
MyDocuments = new List<string>()
{
"b2vg",
"eb5",
"asc"
};
break;
}
SelectedPrinter = value;
}
private void btnAddTray_Click(object sender, RoutedEventArgs e)
{
TrayItem trayItem = new TrayItem { DataContext = cTray.DataContext };
spItems.Children.Add(trayItem);
}
}
}
i am new to mvvm and hope, someone could help me to understand the following:
I have a Model, ViewModel and a View (UserControl), in the MainWindow there are 3 textboxes and the PersonView, which show several persons. This work. Now i want to select one of the persons (binded to SelectedPerson) and show the information in the 3 textboxes.
But i don't know, how to bind the SelectedPerson from PersonViewModel to the textboxes.
I tried to set the datacontext for the textboxes and the usercontrol to the same, and bind the boxes like Text="{Binding SelectedPerson.ID}", but that doesn't work.
Is there a way, to get the selected person from within the UserControl and display the information, or do i need to put the textboxes also in the usercontrol?
Thanks in advance,
Flo
PersonModel.cs:
namespace MVVMExample.Model
{
public class PersonModel: INotifyPropertyChanged
{
public int ID { get; set; }
private string forname;
public string Forname
{
get { return forname; }
set {
forname = value;
RaisePropertyChanged("Forname");
}
}
private string surname;
public string Surname
{
get { return surname; }
set {
surname = value;
RaisePropertyChanged("Surname");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
PersonViewModel.cs:
public class PersonViewModel
{
public PersonViewModel()
{
Persons = new ObservableCollection<PersonModel>();
LoadPersons();
}
public ObservableCollection<PersonModel> Persons
{
get;
set;
}
public PersonModel SelectedPerson { get; set; }
public void LoadPersons()
{
ObservableCollection<PersonModel> persons = new ObservableCollection<PersonModel>();
persons.Add(new PersonModel { ID = 1, Forname = "Thomas", Surname = "Sogen" });
persons.Add(new PersonModel { ID = 2, Forname = "Seth", Surname = "Xu" });
persons.Add(new PersonModel { ID = 3, Forname = "Derik", Surname = "Mayers" });
persons.Add(new PersonModel { ID = 4, Forname = "Daisy", Surname = "Doros" });
Persons = persons;
}
}
PersonView.xaml (UserControl):
<UserControl x:Class="MVVMExample.Views.PersonView"
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:MVVMExample.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="400">
<Grid>
<DataGrid Name="PersonDataGrid" Grid.Row="4" AutoGenerateColumns="False" ItemsSource="{Binding Persons, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" CanUserAddRows="False" IsReadOnly="True" HeadersVisibility="Column" FontSize="14" SelectionMode="Single" SelectedItem="{Binding SelectedPerson}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" Width="*"/>
<DataGridTextColumn Header="Forname" Binding="{Binding Forname}" Width="*"/>
<DataGridTextColumn Header="Surname" Binding="{Binding Surname}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
PersonView.xaml.cs:
public partial class PersonView : UserControl
{
public PersonView()
{
InitializeComponent();
this.DataContext = new MVVMExample.ViewModel.PersonViewModel();
}
}
MainWindow.xaml
<Window x:Class="MVVMExample.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:MVVMExample"
xmlns:views="clr-namespace:MVVMExample.Views"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0"/>
<TextBox Grid.Row="1"/>
<TextBox Grid.Row="2"/>
<views:PersonView x:Name="PersonViewControl" Loaded="PersonViewControl_Loaded" Grid.Row="3"/>
</Grid>
</Window>
What I'm doing is quite simple. I`m hosting list of UserControls in an ItemControl.
I made up a test application with a simple TextBox as a UserControl, it works as expected. But when I incorporate this in my main code, the ItemControl does not display all the Text Boxes. It always limits it to 3, and the values in the text boxes don`t get updated.
Is the IDE limiting how many UserControls I can view in the designer when I have other controls? When I execute the code, I do see all the UserControls. I just need to show 6 and not 100s.I would like to see all the UserControls in the designer in my main code and not just the test application.
The code between the test application and my main application is the same.
Here is the code, I`m attaching the pictures of what I see in the Designer.
/// <summary>
/// View Model Class for the MainWindow.
/// </summary>
class AViewModel : INotifyPropertyChanged
{
public AViewModel()
{
ZList = new ObservableCollection<StringObject>
{
new StringObject {Value = "1"},
new StringObject {Value = "2"},
new StringObject {Value = "3"},
new StringObject {Value = "4"},
new StringObject {Value = "5"},
new StringObject {Value = "6"},
new StringObject {Value = "7"},
};
}
private ObservableCollection<StringObject> zlist;
public ObservableCollection<StringObject> ZList
{
get { return zlist; }
set
{
zlist = value;
OnPropertyChanged("ZList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class StringObject
{
public string Value { get; set; }
}
}
XML of Main Window
<Window x:Class="IssueWPF.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:IssueWPF"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:AViewModel></local:AViewModel>
</Window.DataContext>
<Grid>
<Viewbox>
<ItemsControl ItemsSource="{Binding ZList}" Height="220" Margin="0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Viewbox>
</Grid>
</Window>
Given the following classes (where ViewModelBase contains the INotifyPropertyChanged members)
namespace WpfApplication1
{
class ViewModel : ViewModelBase
{
private Person selectedPerson;
public ObservableCollection<Person> Persons { get; set; }
public Person SelectedPerson
{
get
{
return selectedPerson;
}
set
{
selectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
public ViewModel()
{
Persons = new ObservableCollection<Person>();
Persons.Add(new Person { FirstName = "John", LastName = "Smith" });
Persons.Add(new Person { FirstName = "Jane", LastName = "Jones" });
SelectedPerson = new Person();
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
And the following 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:vm="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:ViewModel />
</Window.DataContext>
<Grid>
<StackPanel>
<ListBox ItemsSource="{Binding Persons}"
DisplayMemberPath="FirstName"
SelectedItem="{Binding SelectedPerson}"/>
<StackPanel DataContext="{Binding SelectedPerson}">
<TextBox Text="{Binding FirstName}" />
<TextBox Text="{Binding LastName}" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
If the value in the TextBox bound to FirstName is changed, the change is automatically reflected in the ListBox. Assuming that I add a Button control and associated Command, is there a way instead to have the changed value propagated to the ListBox only if that Button has been pressed?
I have a ListView that contains two types of objects, single and multiple.
The single is a ordinary TextBlock while the multiple is a ComboBox with items.
I'm trying to group the items in the ComboBox without success. Is it possible? Or should I go for a different approach?
What I'm trying to achieve:
[ComboBox v]
[Header ]
[ Item]
[ Item]
[Header ]
[ Item]
It is possible. Use a ListCollectionView with a GroupDescription as the ItemsSource and just provide a GroupStyle to your ComboBox. See sample below:
XAML:
<Window x:Class="StackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow"
xmlns:uc="clr-namespace:StackOverflow.UserControls"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ComboBox x:Name="comboBox">
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Window>
Code-behind:
namespace StackOverflow
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//this.comboBox.DataContext = this;
List<Item> items = new List<Item>();
items.Add(new Item() { Name = "Item1", Category = "A" });
items.Add(new Item() { Name = "Item2", Category = "A" });
items.Add(new Item() { Name = "Item3", Category = "A" });
items.Add(new Item() { Name = "Item4", Category = "B" });
items.Add(new Item() { Name = "Item5", Category = "B" });
ListCollectionView lcv = new ListCollectionView(items);
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
this.comboBox.ItemsSource = lcv;
}
}
public class Item
{
public string Name { get; set; }
public string Category { get; set; }
}
}