I have an items control with items source, and i want it to display previews
<ItemsControl ItemsSource="{Binding Path=Children}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Preview}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Preview is a grid
public class Child
{
public Grid Preview { get; set; }
public Child()
{
Preview = new Grid();
Preview.Children.Add(new TextBlock() { Text = "Test"});
Preview.Background = new SolidColorBrush(Colors.Red);
}
}
But it doesn't seem to render anything, what am I missing?
try like this,
<ItemsControl ItemsSource="{Binding Children}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Preview}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
or
<ItemsControl ItemsSource="{Binding Path=Children}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Preview}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
there is no datacontext, so it didnt display anything.
Related
I'm working on a wpf window to edit the user settings.
This is what I did so far:
<ListView Grid.Row="1"
ItemsSource="{Binding Source={x:Static properties:Settings.Default}, Path=PropertyValues}"
HorizontalContentAlignment="Stretch" Background="LightGray"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel HorizontalAlignment="Stretch"
IsEnabled="{Binding DataContext.Enabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<Label Width="200" Content="{Binding Name}"/>
<Label Width="200" Content="{Binding Path=Property.PropertyType}" Foreground="Gray" FontStyle="Italic"/>
<ContentControl VerticalContentAlignment="Center" Content="{Binding Path=PropertyValue}">
<ContentControl.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type sys:Boolean}">
<CheckBox IsChecked="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:String}">
<TextBox Text="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Int32}">
<TextBox Text="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ResourceDictionary>
</ContentControl.Resources>
</ContentControl>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The values are showing but they're not updated in Properties.Settings.Default when I change and save them with Properties.Settings.Default.Save();.
Is the two way binding correct?
Thanks
As suggested in the comments and in this answer, I need to encapsulate the System.Configuration.SettingsPropertyValue into a ViewModel that implements INotifyPropertyChanged. Otherwise the binding won't work.
ViewModel:
public class SettingsPropertyValueProxy : INotifyPropertyChanged
{
public string Name { get; }
public Type PropertyType => PropertyValue.GetType();
public object PropertyValue
{
get
{
return Properties.Settings.Default[Name];
}
set
{
try
{
Properties.Settings.Default[Name] = Convert.ChangeType(value, PropertyType);
Properties.Settings.Default.Save();
}
catch
{ }
}
}
public SettingsPropertyValueProxy(string name)
{
Name = name;
Properties.Settings.Default.PropertyChanged += (sender, e) => _OnPropertyChanged(e.PropertyName);
}
private void _OnPropertyChanged(string propertyName)
{
if (propertyName == Name) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PropertyValue)));
}
public event PropertyChangedEventHandler PropertyChanged;
}
New Property to bind:
public IEnumerable<SettingsPropertyValueProxy> Values { get; }
= Properties.Settings.Default.Properties
.Cast<SettingsProperty>()
.Select(p => new SettingsPropertyValueProxy(p.Name))
.OrderBy(p => p.Name)
.ToArray();
Correct View and Correct DataTemplates:
<ListView Grid.Row="1"
ItemsSource="{Binding Path=Values}"
HorizontalContentAlignment="Stretch" Background="LightGray"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel HorizontalAlignment="Stretch"
IsEnabled="{Binding DataContext.Enabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<Label Width="200" Content="{Binding Path=Name}"/>
<Label Width="200" Content="{Binding Path=PropertyType}" Foreground="Gray" FontStyle="Italic"/>
<!--<TextBox Text="{Binding Path=PropertyValue, Mode=TwoWay}"/>-->
<ContentControl VerticalContentAlignment="Center" Content="{Binding Path=PropertyValue}">
<ContentControl.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type sys:Boolean}">
<CheckBox IsChecked="{Binding Path=PropertyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}, Path=DataContext}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:String}">
<TextBox Text="{Binding Path=PropertyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}, Path=DataContext}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type sys:Int32}">
<TextBox Text="{Binding Path=PropertyValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}, Path=DataContext}"/>
</DataTemplate>
</ResourceDictionary>
</ContentControl.Resources>
</ContentControl>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want to create a list of TextBox in binding with ObservableCollection<String> in a ViewModel but i have a problem. The binding performs only by source to dialog but it not works by dialog to source
in my ViewModel i have
private ObservableCollection<String> _ListSashDim;
public ObservableCollection<String> ListSashDim
{
get { return _ListSashDim; }
set {
if (_ListSashDim != value)
{
_ListSashDim = value;
this.RaisePropertyChanged("ListSashDim");
}
}
}
the list is initialized as below
private ObservableCollection<string> createListSashPosition(int numAnte)
{
ObservableCollection<string> ls = new ObservableCollection<string>();
for (int i = 0; i < numAnte; i++)
{
ls.Add("X");
}
return ls;
}
in my Xaml i have a DataTemplate
<!--#region DataTemplate ListSashDim-->
<DataTemplate x:Key="DataTemplateSashDim">
<ItemsControl>
<StackPanel Orientation="Vertical" Width="116" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="10" HorizontalAlignment="Center" Text="Sash Dim"></TextBlock>
<TextBox x:Name="tbSashDim" Width="90" Text="{Binding Path=.,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" ></TextBox>
</StackPanel>
</ItemsControl>
</DataTemplate>
<!--#endregion-->
and an ItemsControl in a StackPanel
<StackPanel
Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center" FlowDirection="LeftToRight"
Margin="0,10,0,0">
<ItemsControl ItemsSource="{Binding ListSashDim, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0" ItemTemplate="{DynamicResource DataTemplateSashDim}" Padding="8" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
Thanks so much
Manuel
I am creating 'Lessons' tab in my application. The problem is in displaying data.
Timetable(List<DayInfo>) is binded to ItemsControl. Each DayInfo is an item in this ItemsControl. I tried to bind Exams collection to nested ItemsControl placed in ItemTemplate, but It's not working.
I'd like to know what I'm doing wrong. I guess my Exams binding is the problem.
Timetable:
private List<DayInfo> timetable;
public List<DayInfo> Timetable
{
get { return timetable; }
set
{
timetable = value;
NotifyOfPropertyChange(() => Timetable);
}
}
There is DayInfo.cs:
public class DayInfo : IValue
{
public string DayName { get; }
public List<ExamEntry> Exams { get; }
...
}
ExamEntry.cs:
public class ExamEntry : DayEntry, IValue
{
public string Description { get; }
...
}
XAML code:
<ItemsControl
ItemsSource="{Binding Timetable}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
...
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"
Margin="0">
</StackPanel>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label
Content="{Binding DayName}" /> <!-- It still works -->
<ItemsControl
ItemsSource="{Binding Exams}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
Content="{Binding Description}" /> <!-- It's not displayed -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Everything is fine with this piece of code. I've forgotten about another part of project, where Timetable was bugged. Sorry for confusion.
this is the data template using my ViewModel
<DataTemplate DataType="{x:Type viewModels:MultipleKeysSectionViewModel}" >
<views:TabListItemUserControl Text="{Binding Header}"/>
</DataTemplate>
here is my list of radio buttons
<ListView ItemsSource="{Binding Tabs.Keys}" Grid.Column="1" HorizontalAlignment="Right" Visibility="{Binding IsMultiple, Converter={StaticResource boolToVis}} SelectedItem="{Binding SelectedParameterName}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding}" Margin="0,0,5,0" GroupName="FilterParameters"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
here is my property
private string _selectedParameterName;
public string SelectedParameterName
{
get { return _selectedParameterName; }
set
{
_selectedParameterName = value;
RaisePropertyChanged(() => SelectedParameterName);
}
}
this is my the collection I bind the ListView into
public Dictionary<string, RegisterListViewModel> Tabs { get; set; }
however when I clicked the radio button it doesn't go to Set of the SelectedParameterName property
only when i hit the "box" containing the name of the radio button Set is executed.
Has anyone come across this issue before ?
the IsChecked property of the RadioButton is not bound to anything, therefore clicking on the RadioButton will do nothing.
Change your RadioButton to this:
<RadioButton Content="{Binding}" Margin="0,0,5,0"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"/>
Every example and I article I found, is about grouping items by one property and displaying it. But what I have, is a strongly type group key, which I want to display. Here is models and grouping logic:
The item interface
public interface IItem {
string Title { get; }
string ToolTip { get; }
object Icon { get; }
Type GroupType { get; }
}
IItem has many implementations like this:
public class Item : IItem {
public string Title { get; private set; }
public string ToolTip { get; private set; }
public object Icon { get; private set; }
// I have many implementation of IGroup which I will use them in GroupType properties.
public Type GroupType { get { return SomeGroupTypeHere; } }
}
And here is the group interface:
public interface IGroup {
string Name { get; }
object Icon { get; }
}
and it has many implementations too.
I collect them in my view model (by getting help from Autofac):
public class MyViewModel {
private readonly IEnumerable<IGrouping<IGroup, IItem>> _items;
public MyViewModel(IEnumerable<IGroup> groups, IEnumerable<IItem> items){
_items = items.GroupBy(t => {
var g = groups.First(u => u.GetType() == t.GroupType);
return g;
});
}
public IEnumerable<IGrouping<IGroup, IItem>> Items {
get { return _items; }
}
}
Now, the problem is, how to display this grouped items, in a ItemsControl?
<ItemsControl ItemsSource="{Binding Items}" Margin="20 20 20 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate >
<!-- here is my template that uses IItem properties, example: -->
<Button Content="{Binding Title}"
ToolTip="{Binding ToolTip}"/>
</DataTemplate >
</ItemsControl.ItemTemplate>
</ItemsControl>
The code, just only displays the first item in each group, and I have no idea what to do to show group headers (that use IGroup properties) and also show all items in each group. Any suggestion please? Any article or blog-post will be very useful. Thanks in advance.
You want to use HierarchicalDataTemplate when you want to display Grouped data, Change your ItemsControl.ItemTemplate to a `HierarchialDataTemplate'.
Sample (and Untested) HierarchialDataTemplate:
<ItemsControl ItemsSource="{Binding Items}" Margin="20 20 20 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding}">
<Button Content="{Binding Title}" ToolTip="{Binding ToolTip}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate >
<Button Content="{Binding Title}" ToolTip="{Binding ToolTip}"/>
</DataTemplate >
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Refer to this blogpost for step-by-step approach to HierarchialDataTemplates.
UPDATE
I have tried the above HierarchialDataTemplate with your code and it doesnt seem to work. However, if I replace ItemsControl with TreeView, it does work as expected.
So, I guess, you might want to have nested ItemControl for your case, Tested sample code as below:
<ItemsControl ItemsSource="{Binding Items}" Margin="20 20 20 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding Title}" ToolTip="{Binding ToolTip}"/>
<ItemsControl ItemsSource="{Binding}" Margin="15,0,0,0">
<ItemsControl.ItemTemplate>
<DataTemplate >
<Button Content="{Binding Title}" ToolTip="{Binding ToolTip}"/>
</DataTemplate >
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is the screen shot with this nested ItemsControls.
UPDATE 2
I think you need to update the template to display Group, the current template doesnt do that.
Updated Template is below:
<ItemsControl ItemsSource="{Binding Items}" Margin="20 20 20 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding Key.Name}" />
<ItemsControl ItemsSource="{Binding}" Margin="15,0,0,0">
<ItemsControl.ItemTemplate>
<DataTemplate >
<Button Content="{Binding Title}" ToolTip="{Binding ToolTip}"/>
</DataTemplate >
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the resulting Screenshot: