I have a ListView that is supposed to display objects of class Sensor, for which I created a simple (for now) DataTemplate.
In order to further design this DataTemplate in Expression Blend, I created Sample Data from Class as shown in the docs (although I am using Blend for Visual Studio 2013, but it seems to be the same).
I can successfully get the Sample Data I created being displayed in a ListView, but it is not using the DataTemplate I created, since the elements displayed seem to belong to a different, "design" namespace:
The qualified name of my class is Miotec.BioSinais.ModeloDomínio.Sensor;
(But) the qualified name of the displayed class is _.di0.Miotec.BioSinais.ModeloDomínio.Sensor.
What am I doing wrong? (code and screenshot below)
<Window
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:dominio="clr-namespace:Miotec.BioSinais.ModeloDomínio;assembly=Miotec.BioSinais"
mc:Ignorable="d"
x:Class="Miotec.ProtótipoColeta.ColetaConfigView"
x:Name="Window"
Title="ColetaConfigView"
Width="640" Height="480">
<Window.Resources>
<DataTemplate DataType="{x:Type dominio:Sensor}">
<Border>
<TextBlock Text="{Binding Nome}"/>
</Border>
</DataTemplate>
</Window.Resources>
<DockPanel x:Name="LayoutRoot">
<Grid x:Name="PainelCentral">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel x:Name="PainelSetupsSensores" Background="#FFB8E6E8"/>
<DockPanel x:Name="PainelSensoresDisponiveis" Background="#FFC5E2A8"
Grid.RowSpan="2" Grid.Column="1"
DataContext="{Binding ReceiverAtivo}"
d:DataContext="{d:DesignData /SampleData/ReceiverSimuladoSampleData.xaml}">
<ListView ItemsSource="{Binding Sensores}" Margin="10"/>
</DockPanel>
</Grid>
</DockPanel>
</Window>
====
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Miotec.BioSinais.ModeloDomínio
{
public abstract class Sensor : INotifyPropertyChanged
{
public abstract string Nome { get; set; }
public virtual int NívelBateria { get; set; }
public virtual int NívelSinalWireless { get; set; }
public virtual EstadoSensor Estado { get; protected set; }
public ObservableCollection<Canal> Canais { get; protected set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged (string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
==============
Related
https://stackoverflow.com/a/36192552/9387175
In this answer the user suggests that the comboBoxAdaptor can be used to add an item to a combo box even if it does not exist in the item source. I do in fact see that it is working in the code, but I can't figure out why it refuses to display. The normal combo box functions correctly in the below example, the comboBoxAdaptor is not visible. Am I missing something like styles or templates? I can't seem to find the right combination.
My xaml:
<Window x:Class="WpfApp1.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:adapters="clr-namespace:WpfApp1.Adapters"
mc:Ignorable="d"
Title="MainWindow"
Height="200"
Width="650">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="210" />
<ColumnDefinition Width="210" />
</Grid.ColumnDefinitions>
<adapters:ComboBoxAdaptor Grid.Column="0"
AllowNull="False"
Height="80"
ItemsSource="{Binding Path=DataEntries}"
SelectedItem="{Binding Path=DataEntry}">
<ComboBox Height="80" />
</adapters:ComboBoxAdaptor>
<ComboBox Grid.Column="1"
Height="80"
ItemsSource="{Binding Path=DataEntries}"
SelectedItem="{Binding Path=DataEntry}"
DisplayMemberPath="Name"
SelectedValuePath="Name" />
</Grid>
</Window>
My Code:
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SampleViewModel vm = new SampleViewModel();
DataContext = vm;
}
}
public class SampleDataClass
{
public string Name { get; set; }
public SampleDataClass(string name)
{
Name = name;
}
}
public class SampleViewModel : INotifyPropertyChanged
{
private readonly IList<SampleDataClass> _dataEntries;
private string _dataEntry;
public event PropertyChangedEventHandler PropertyChanged;
public SampleViewModel()
{
IList<SampleDataClass> list = new List<SampleDataClass>();
list.Add(new SampleDataClass("tools"));
list.Add(new SampleDataClass("set"));
list.Add(new SampleDataClass("sort"));
list.Add(new SampleDataClass("flap"));
_dataEntries = list;
}
public IList<SampleDataClass> DataEntries
{
get { return _dataEntries; }
}
public string DataEntry
{
get
{
return _dataEntry;
}
set
{
if (_dataEntry == value) {return;}
_dataEntry = value;
OnPropertyChanged("DataEntry");
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Turns out that I was missing the style that links the ComboBox to the content of the ContentControl (ComboBoxAdaptor)
Style Example
<Style TargetType="adapters:ComboBoxAdaptor">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="adapters:ComboBoxAdaptor">
<ContentPresenter Content="{TemplateBinding ComboBox}"
Margin="{TemplateBinding Padding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I am a newbie to WPF and while I have read lots of theory and articles, I am unable to put it all together in a working solution.
Presently, I wish to implement dynamic multiple views in a window which could be selected by the user using buttons. The target is very much like one given in the question,
WPF : dynamic view/content
Can somebody please share with me a working code, of simplest implementation of the above. Just a window which contains two grids - one grid has two buttons - second grid changes background color depending on which button is clicked. From there on , I can take things further.
Thank you very much.
Use MVVM
It's a design approach. Basically you treat your Window as shell, and it's responsible for swapping views.
To simplify this snippet, I've referenced MvvmLight .
The Window contains ContentControl which dynamically displays the relevant view
Each dynamic view can communicate with the shell Window (using MvvmLight's Messenger) and tell it to change the view to something else.
MainWindow.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"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel></local:MainWindowViewModel>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="0" Command="{Binding ChangeFirstViewCommand}">Change View #1</Button>
<Button Grid.Row="0" Grid.Column="1" Command="{Binding ChangeSecondViewCommand}">Change View #2</Button>
<ContentControl Grid.Row="1" Grid.ColumnSpan="2" Content="{Binding ContentControlView}"></ContentControl>
</Grid>
</Window>
MainWindowViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public class MainWindowViewModel : ViewModelBase
{
private FrameworkElement _contentControlView;
public FrameworkElement ContentControlView
{
get { return _contentControlView; }
set
{
_contentControlView = value;
RaisePropertyChanged("ContentControlView");
}
}
public MainWindowViewModel()
{
Messenger.Default.Register<SwitchViewMessage>(this, (switchViewMessage) =>
{
SwitchView(switchViewMessage.ViewName);
});
}
public ICommand ChangeFirstViewCommand
{
get
{
return new RelayCommand(() =>
{
SwitchView("FirstView");
});
}
}
public ICommand ChangeSecondViewCommand
{
get
{
return new RelayCommand(() =>
{
SwitchView("SecondView");
});
}
}
public void SwitchView(string viewName)
{
switch (viewName)
{
case "FirstView":
ContentControlView = new FirstView();
ContentControlView.DataContext = new FirstViewModel() { Text = "This is the first View" };
break;
default:
ContentControlView = new SecondView();
ContentControlView.DataContext = new SecondViewModel() { Text = "This is the second View" };
break;
}
}
}
}
FirstView.xaml
<UserControl x:Class="WpfApplication1.FirstView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label>This is the second view</Label>
<Label Content="{Binding Text}" />
<Button Command="{Binding ChangeToSecondViewCommand}">Change to Second View</Button>
</StackPanel>
</UserControl>
FirstViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApplication1
{
public class FirstViewModel : ViewModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
RaisePropertyChanged("Text");
}
}
public ICommand ChangeToSecondViewCommand
{
get
{
return new RelayCommand(() =>
{
Messenger.Default.Send<SwitchViewMessage>(new SwitchViewMessage { ViewName = "SecondView" });
});
}
}
}
}
SecondView.xaml
<UserControl x:Class="WpfApplication1.SecondView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label>This is the second view</Label>
<Label Content="{Binding Text}" />
<Button Command="{Binding ChangeToFirstViewCommand}">Change to First View</Button>
</StackPanel>
</UserControl>
SecondViewModel.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApplication1
{
public class SecondViewModel : ViewModelBase
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
RaisePropertyChanged("Text");
}
}
public ICommand ChangeToFirstViewCommand
{
get
{
return new RelayCommand(() =>
{
Messenger.Default.Send<SwitchViewMessage>(new SwitchViewMessage { ViewName = "FirstView" });
});
}
}
}
}
SwitchViewMessage.cs
namespace WpfApplication1
{
public class SwitchViewMessage
{
public string ViewName { get; set; }
}
}
Trying to bind a listbox to an object. Code runs without errors but for some reason sample data doesn't appear in listbox
XAML: ucDataBindingObject.xaml
<UserControl x:Class="TheProject.UserControls.ucDataBindingObject"
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"
Name="DataBindingObject"
Width="Auto"
Height="Auto"
mc:Ignorable="d">
<Grid Width="130"
Height="240"
Margin="0">
<ListBox Name="lbObject"
Width="110"
Height="80"
Margin="10,7,-9.6,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
DisplayMemberPath="Name"
ItemsSource="{Binding ElementName=ucDataBindingObject,
Path=Clients}" />
</Grid>
</UserControl>
C#: ucDataBindingObject.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
namespace TheProject.UserControls
{
public partial class ucDataBindingObject : UserControl
{
public List<Client> Clients { get; set; }
public ucDataBindingObject()
{
Clients = new List<Client>();
Clients.Add(new Client(1, "David")); // sample data
Clients.Add(new Client(2, "Helen"));
Clients.Add(new Client(3, "Joe"));
InitializeComponent();
}
}
C# Client.cs
using System;
using System.Linq;
namespace TheProject.UserControls
{
public class Client
{
public int ID { get; set; }
public string Name { get; set; }
public Client(int id, string name)
{
this.ID = id;
this.Name = name;
}
}
}
Update your ItemsSource Binding as
ItemsSource="{Binding Path=Clients}"
and in the constructor of your view, set its DataContext after InitializeComponents as
this.DataContext = this;
there is no element named ucDataBindingObject, its the class name of your usercontrol
OR change the elementname in binding to DataBindingObject, which you named your usercontrol
I want to bind an entity property (say Salary) to a property of a XAML element (like a TextBox.Text)
and use this binding to save Text of TextBox to salary field which is bound as a entity property to 'Text' of some TextBox.
Something like the following :
<Grid DataContext="Employee">
<TextBox Text="{Binding Path=Salary, Mode=TwoWay}"/>
</Grid>
you just can bind Properties in xaml - so your salary have to be a property and not a field. if your Employee is the class with the salary you can set datacontext to an instance of it. you can do it in xaml or codebehind or with binding.
public class Employee //implement INotifyPropertyChanged to get the power of binding :)
{
public decimal Salary {get;set}
}
view.xaml
<Grid>
<Grid.DataContext>
<local:Employee/>
</Grid.DataContext>
<TextBox Text="{Binding Path=Salary, Mode=TwoWay}"/>
</Grid>
you can set the datacontext in many ways
XAML Two-Way Binding, 'Windows Universal' style, step-by-step
In Visual Studio 2017, create a Visual C# blank app (Universal Windows). Name it 'MyProject'.
Add a class Employee to it, and then modify boilerplate code as follows:
// Employee.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace MyProject
{
public class Employee : INotifyPropertyChanged
{
private string salary;
public string Salary
{
get
{
return this.salary;
}
set
{
if (value != this.salary)
{
this.salary = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
// This method MUST BE called by the Set accessor of each property for TwoWay binding to work.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// Constructor with one parameter
public Employee(string annualSalary) { salary = annualSalary; }
}
}
Notice that class Employee implements the INotifyPropertyChanged Interface.
Add class EmployeeViewModel to project, and modify boilerplate code as follows:
// EmployeeViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyProject
{
public class EmployeeViewModel
{
private Employee defaultEmployee = new Employee("50000");
public Employee DefaultEmployee { get { return this.defaultEmployee; } }
}
}
Modify MainPage.xaml.cs boilerplate code as follows
//MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace MyProject
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.ViewModel = new EmployeeViewModel();
}
public EmployeeViewModel ViewModel { get; set; }
}
}
Modify MainPage.xaml boilerplate code as follows:
<Page
x:Class="MyProject.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyProject"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--TextBlock will provide visual feedback that the two-way binding is working-->
<TextBlock x:Name="Control" Text="{x:Bind ViewModel.DefaultEmployee.Salary, Mode=OneWay}" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center"/>
<!--TextBox has two-way binding-->
<TextBox x:Name="Input" Text="{x:Bind ViewModel.DefaultEmployee.Salary, Mode=TwoWay}" Margin="10" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Center"/>
<!--Button does nothing other than allow TextBox to lose focus-->
<Button x:Name="btn1" Content="Hello" Grid.Column="1" Grid.Row="3"
Foreground="Green"
HorizontalAlignment="Center"/>
</Grid>
</Page>
Notice, both 'Input' TextBox and 'Control' TextBlock are bound to the same Salary property of DefaultEmployee. The idea is that you edit and change the salary in the 'Input' TextBox, and then you can visually see the Two-Way binding at work, because the 'Control' TextBlock will update. This happens when the 'Input' TextBox loses focus (it is to allow the change of focus, for instance after pressing TAB key, that the 'Hello' button was added - the button in itself does absolutely nothing).
Build and Run. Modify salary, and either TAB or click button:
No you cant do like that. You cant Set the Class name to the DataContext. It should be the instance of Employee class.
The following example successfully binds objects with a ListBox to display them.
However, I would like to create all the objects in one class and then from another class query them with LINQ to fill my XAML ListBox, what would I need to add this example:
XAML:
<Window x:Class="WpfApplication15.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
xmlns:local="clr-namespace:WpfApplication15">
<Window.Resources>
<ObjectDataProvider x:Key="customers" ObjectType="{x:Type local:Customers}"/>
<DataTemplate x:Key="LastNameFirst" DataType="WpfApplication15.Customer">
<StackPanel Margin="10 10 10 0" Orientation="Horizontal">
<TextBlock Text="{Binding Path=LastName}" FontWeight="bold"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding Path=FirstName}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource customers}}"
ItemTemplate="{StaticResource LastNameFirst}"/>
</Grid>
</Window>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication15
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Customer(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
}
public class Customers : List<Customer>
{
public Customers()
{
this.Add(new Customer("Jim", "Thompson"));
this.Add(new Customer("Julie", "Watson"));
this.Add(new Customer("John", "Walton"));
}
}
}
edit: added ToList call to the LINQ query
You can just assign the ItemsSource of the ListBox using LINQ in code-behind for this. Assuming you give your ListBox a name:
<Window x:Class="WpfApplication15.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfApplication15"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300" Title="Window1">
<Window.Resources>
<DataTemplate x:Key="LastNameFirst" DataType="WpfApplication15.Customer">
<StackPanel Margin="10 10 10 0" Orientation="Horizontal">
<TextBlock FontWeight="bold" Text="{Binding Path=LastName}"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding Path=FirstName}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="lstCustomers"
ItemTemplate="{StaticResource LastNameFirst}"/>
</Grid>
</Window>
You can assign to ItemsSource in the Loaded event:
public partial class Window1 : Window
{
public Window1()
{
this.Loaded += new RoutedEventHandler(Window1_Loaded);
InitializeComponent();
}
void Window1_Loaded(object sender, RoutedEventArgs e)
{
Customers customers = new Customers();
lstCustomers.ItemsSource = customers.Where(customer => customer.LastName.StartsWith("W")).ToList();
}
}
Assuming your LINQ query will change depending on some logic, you can re-assign ItemsSource at the appropriate points.
If you want to bind without dipping into code-behind whenever your query logic changes, you're probably better off using a CollectionViewSource, since it has sorting and filtering capabilities (assuming that's what you're after from using LINQ).
Take a look # http://www.codeplex.com/bindablelinq and you should find a bunch of good examples for this.