How to put an Expander inside Datatemplate? - wpf

Strange one.
I have a contentcontrol on a WPF form, this loads a datatemplate within it.
This shows up fine (handwritten summary code so ignore errors/lack of attributes):
<DataTemplate>
<Label Content="Found datatemplate" />
</DataTemplate>
This however renders blank
<DataTemplate>
<Expander Header="Why dont I show">
<Label Content="Found datatemplate" />
</Expander>
</DataTemplate>
I have set the expander to visibile, isexpanded to true etc and no matter what it doesn't render at all.
Confused- is this just not possible?

I've recently done something similar to what you're describing and it worked for me. I have an ItemsControl that binds to a collection of view models, each of which contains a UserControl representing custom content. I implemented the ItemsControl.ItemTemplate to display the custom control inside an Expander like this:
<ItemsControl Margin="0,20,0,0" ItemsSource="{Binding ControlItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="0,0,0,0"
BorderBrush="#E7E7E7"
BorderThickness="0,1,0,0"
Padding="20,0">
<Expander Foreground="#E7E7E7"
IsExpanded="{Binding Path=IsExpanded,
Mode=TwoWay}">
<Expander.Header>
<Grid>
<TextBlock HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="24"
Text="{Binding Title}" />
</Grid>
</Expander.Header>
<DockPanel>
<ScrollViewer MinHeight="250">
<ContentControl Content="{Binding Control}" />
</ScrollViewer>
</DockPanel>
</Expander>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is what my view model looks like:
public class SidePanelControlItem : ModelBase
{
private bool _isExpanded;
public SidePanelControlItem(UserControl control)
{
if (control == null) { throw new ArgumentNullException("control");}
Control = control;
}
public string Title { get; set; }
public UserControl Control { get; private set; }
public bool IsExpanded
{
get { return _isExpanded; }
set
{
_isExpanded = value;
OnPropertyChanged("IsExpanded");
}
}
}

Related

ListBox within WPF TextBox - Chips

I need to add ListBox within a TextBox i.e., CHIPS
Refer the Screen shot: (Expectation)
Just Consider the View Model:
public class Person
{
private ObservableCollection<string> _personList = new ObservableCollection<string>();
public ObservableCollection<string> PersonList
{
get { return _personList; }
set
{
_personList = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("PersonList"));
}
}
private string _personStr = String.Empty;
public string PersonStr
{
get { return _personStr; }
set
{
_personStr = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("PersonStr"));
}
}
public Person()
{
PersonList.Add("IR-Punch");
PersonList.Add("Stack-Overflow");
}
public ICommand BTextCommand
{
get
{
return new DelegateCommand(AppendString);
}
}
public void AppendString()
{
PersonList.Add(PersonStr);
}
}
The working XAML Source Code:
<ItemsControl ItemsSource="{Binding PersonList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }" TextWrapping="Wrap"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBox Text="{Binding PersonStr}" Width="160" VerticalAlignment="Center" />
<Button Command="{Binding BTextCommand}" Content="Add" />
Kindly assist me how to add ListBox within a TextBox. I take care of Sytle. I'm expecting the core idea.
Don't try to embed additional controls within the TextBox, instead embed the ItemsControl and TextBox in a stack panel as shown below:
<Border BorderThickness="1">
<ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding PersonList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBox MinWidth="100" BorderBrush="Transparent" BorderThickness="0" Text="{Binding PersonStr}" />
</StackPanel>
</ScrollViewer>
</Border>
You will want to style the outer Border to look like a TextBox (pretty much just finding the correct BorderBrush) but, as requested, I've left the styling to you.
Please note, I've not actually tried this solution, just penned it as an approach that should work. Let me know if you have any problems with it.

How to bind each button's image source from ListView to individual item from observable collection?

I have a Listview of Buttons like this:
<ListView ItemsSource="{Binding TestList}">
<ListViewItem >
<ListView.ItemTemplate>
<DataTemplate>
<Button Name="test" Grid.Row="0" Grid.Column="10" Grid.ColumnSpan="4" Grid.RowSpan="4" VerticalAlignment="Center" Background="Transparent">
<Button.Template>
<ControlTemplate>
<Grid>
<Image Source="?????????????????????????????????????????????"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</ListView.ItemTemplate>
And the code behind like this:
public class CodeBehind
{
private ObservableCollection<string> testList;
public ObservableCollection<string> TestList
{
get { return testList; }
set
{
testList = value;
}
}
public CodeBehind()
{
dummyModelList = new ObservableCollection<string>() { "/Assets/Image1", "/Assets/Image2", "/Assets/Image3"};
}
}
How to bind each button's image source to individual item from observable collection? I want to do this only in XAML.
What you are looking for is ItemTemplate (Gets or sets the DataTemplate used to display each item.) instead of buttons' template itself.
You use the ItemTemplate to specify the visualization of the data objects. If your ItemsControl is bound to a collection object and you do not provide specific display instructions using a DataTemplate, the resulting UI of each item is a string representation of each object in the underlying collection.
So when you set the ItemTemplate to an instance of DataTemplate, the DataTemplate will be used to render the items. The DataContext of the DataTemplate will be implicitly set to individual items in the bound collection, so you can bind the Image.Source to the DataContext itself using {Binding .} or {Binding}
<ListView ItemsSource="{Binding TestList}">
<ListView.ItemTemplate>
<DataTemplate>
<Button Name="test" Grid.Row="0" Grid.Column="10" Grid.ColumnSpan="4" Grid.RowSpan="4" VerticalAlignment="Center" Background="Transparent">
<Image Source="{Binding .}" />
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You should create a DataTemplate to show any controls in your ItemTemplate of ListView:
<ListView Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto*"/>
<RowDefinition Height="Auto*"/>
</Grid.RowDefinitions>
<Button>
<Image Source="{Binding AddressImage}" Width="20" Grid.Row="0" />
</Button>
<TextBlock Grid.Row="1" TextAlignment="Left" FontWeight="Light"
VerticalAlignment="Center" Text="{Binding UserName}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Model:
public class Person
{
public int IdUser {get; set;}
public string UserName {get; set;}
public string AddressImage {get; set;}
}
code-behind:
public MainWindow()
{
PopulateCollection();
}
private void PopulateCollection()
{
ObservableCollection<Person> personColl = new ObservableCollection<Person>();
for (int i = 0; i <= 10; i++)
{
//here you can set any image what you want
personColl.Add(new Person() { IdUser=i, UserName="I am " + i.ToString(),
AddressImage="Assets/1.png"});
//Assets is a folder with images
}
listView.ItemsSource=personColl;
}

ComboBox Whith a TreeView

I need to create a userControl like a Combobox.
In the items in need a TreeView and a Button.
If I navigate the Tree the Item should go to the Text Box in the Bottom.
If I click the Button the Tree should Collapsed.
My First idea was like This but it isn't good.
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Adresse, Mode=TwoWay}" MaxLength="50" MinWidth="170" Grid.Row="5" Margin="5,2,5,2"/>
<Button Width="25" Margin="2" Click="Down">
<Image Source="/C1_net;component/Images/arrow.jpg" HorizontalAlignment="Left" />
</Button>
</StackPanel>
<StackPanel x:Name="Tree" Orientation="Vertical" Visibility="Collapsed">
<sdk:TreeView Height="200" Name="treeView1" Width="200" />
<Button Content="{Binding Path=ApplicationStrings.OKButton, Source={StaticResource ResourceWrapper}}" Width="75" Margin="5" Click="OnOk" HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
</Grid>
If I switch to Visible the Control needs more space.
So I need to bring the Tree in Front of the Rest of the Window.
Any ideas?
Ok.
I think you should revisit your interaction.
my problemm wase to think if i select i Item, The Tree wood be closed.
I will navigate in a Hirarchical DataObjekt and Put the Path as selectet Item.
So now I will to somting like this:
public interface ITreeViewItemModel
{
string SelectedValuePath { get; }
bool IsExpanded { get; set; }
bool IsSelected { get; set; }
IEnumerable<ITreeViewItemModel> GetHierarchy();
IEnumerable<string> GetDisplayHierarchy();
IEnumerable<ITreeViewItemModel> GetChildren();
}
and.
public class ComboBoxTreeView : ComboBox
{
private ExtendedTreeView _treeView;
private ContentPresenter _contentPresenter;
public ComboBoxTreeView()
{
this.DefaultStyleKey = typeof(ComboBoxTreeView);
}
......
I found This http://vortexwolf.wordpress.com/2011/04/29/silverlight-combobox-with-treeview-inside/

change the template of an item after clicking on it

i have a class named :
public class CountryTemplateSelector : ContentControl
{
public DataTemplate TrueTemplate
{
get;
set;
}
public DataTemplate FalseTemplate
{
get;
set;
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Shopping_Ingredients itemAux = item as Shopping_Ingredients;
if (itemAux != null)
{
if (itemAux.IsMarked == true)
return TrueTemplate;
else
return FalseTemplate;
}
return base.SelectTemplate(item, container);
}
public virtual DataTemplate SelectTemplate(object item, DependencyObject container)
{
return null;
}
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
ContentTemplate = SelectTemplate(newContent, this);
}
}
and a DataTemplate declared in App.xaml :
<DataTemplate x:Key="SelectorForCheckbox">
<local:CountryTemplateSelector Content="{Binding}">
<local:CountryTemplateSelector.TrueTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="82">
<CheckBox Name="cb1" FontSize="15" IsChecked="{Binding Path=IsMarked, Mode=TwoWay}" Margin="0,4" RenderTransformOrigin="0.485,0.365" VerticalContentAlignment="Bottom" />
<TextBlock Text="{Binding AmountToString}" Margin="15,0,5,0" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="24"/>
</StackPanel>
</DataTemplate>
</local:CountryTemplateSelector.TrueTemplate>
<local:CountryTemplateSelector.FalseTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="82">
<CheckBox Name="cb1" FontSize="15" IsChecked="{Binding Path=IsMarked, Mode=TwoWay}" Margin="0,4" RenderTransformOrigin="0.485,0.365" VerticalContentAlignment="Bottom" />
<TextBlock Text="TEST" Margin="15,0,5,0" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="24"/>
</StackPanel>
</DataTemplate>
</local:CountryTemplateSelector.FalseTemplate>
</local:CountryTemplateSelector>
</DataTemplate>
and a LongListSelector :
<toolkit:LongListSelector x:Name="recipe1" Background="Transparent"
ItemTemplate="{StaticResource SelectorForCheckbox}"
ListHeaderTemplate="{StaticResource citiesListHeader}"
ListFooterTemplate="{StaticResource citiesListFooter}"
GroupHeaderTemplate="{StaticResource groupHeaderTemplate}"
GroupItemTemplate="{StaticResource groupItemTemplate}" >
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
</toolkit:LongListSelector>
The LongListSelector launches ok, and the templates are shown ok. The problem is that i would like to be able to change the template of the specific item clicked. How can i do so?
We should be able to set the templates in code. See this StackOverflow question. Make sure that all the templates needed are resources in the App.xaml or in your specific UserControl. My example is from a button click, but the same approach should apply elsewhere in code. I'm not 100% certain it should be cast to ControlTemplate. It will probably very per template.
public void CLick_Method(object sender, RoutedEventArgs e)
{
this.recipe1.ItemTemplate = (ControlTemplate)Resources["SelectorForX"];
this.recipe1.ListHeaderTemplate= (ControlTemplate)Resources["NewListHeaderTemplate"];
// etc.
}

Two views of the same ViewModel within a user control

I have a re-usable usercontrol with a viewmodel behind it. I'm trying to switch between different views of the same data. Currently trying to use a Mode property on the VM to accomplish this.
I've created a DataTemplateSelector like so:
<UserControl x:Class="MyUserControl">
<UserControl.Resources>
<DataTemplate x:Key="ColumnTemplate">
<StackPanel>
<Label Text="{Binding Name}"></Label>
<Label Text="{Binding Address}"></Label>
<Label Text="{Binding Occupation}"></Label>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AvatarTemplate">
<StackPanel>
<Image Source="{Binding ProfilePicture}"></Image>
<Label Text="{Binding Name}"></Label>
</StackPanel>
</DataTemplate>
<local:DisplayTemplateSelector ColumnTemplate="{StaticResource ColumnTemplate}" AvatarTemplate="{StaticResource AvatarTemplate}" x:Key="displayTemplateSelector" />
</UserControl.Resources>
<Grid>
<ContentControl Name="cpDisplay" Content="{Binding}" ContentTemplateSelector="{StaticResource displayTemplateSelector}" />
</Grid>
</UserControl>
With the class:
class DisplayTemplateSelector : DataTemplateSelector
{
public DataTemplate ColumnTemplate {get;set;}
public DataTemplate AvatarTemplate {get;set;}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
MainViewModel vm = (MainViewModel)item;
switch (vm.Mode)
{
case MainViewModel.DisplayMode.Column:
return ColumnTemplate;
case MainViewModel.DisplayMode.Avatar:
return AvatarTemplate;
default:
return AvatarTemplate;
}
}
}
This usercontrol sits in MyWindow:
<Grid>
<controls:MyUserControl x:Name="MyUserControl" DataContext="{Binding}" Margin="0"/>
</Grid>
Which is instantiated with my viewmodel:
MyWindow w = new MyWindow(_vm);
w.Show();
The problem I have is that item is null during MainViewModel vm = (MainViewModel)item. It's like I'm trying to set the datatemplate based on data, before the data is bound?
Is there anyway to choose the desired datatemplate not based on the dataobject - but as a property or similar on the usercontrol?
There are many ways, but here are a couple:
<!-- assumes you have a data template selector implementation available as resource MyContentSelector -->
<ContentControl Content="{StaticResource MainViewModel}" ContentTemplateSelector="{StaticResource MyContentSelector}"/>
or:
<!-- assumes you have appropriate boolean properties on your VM -->
<Grid>
<ContentControl Content="{StaticResource MainViewModel}" ContentTemplate="{StaticResource column}" Visibility="{Binding IsColumnVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ContentControl Content="{StaticResource MainViewModel}" ContentTemplate="{StaticResource avatar}" Visibility="{Binding IsAvatarVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</Grid>
See DataTemplateSelector Class
DataTemplateSelector
Ok, finally got this to work how I needed by using a property on the usercontrol and some code behind:
public enum DisplayMode
{
Column,
Avatar
}
public DisplayMode Mode { get; set; }
public MyUserControl()
{
InitializeComponent();
Mode = DisplayMode.Avatar;
}
private void MyUserControl_Loaded(object sender, RoutedEventArgs e)
{
switch (Mode)
{
case DisplayMode.Column:
cpDisplay.ContentTemplate = (DataTemplate)this.Resources["ColumnTemplate"];
cpDisplay.ApplyTemplate();
break;
case DisplayMode.Avatar:
cpDisplay.ContentTemplate = (DataTemplate)this.Resources["AvatarTemplate"];
cpDisplay.ApplyTemplate();
break;
}
}
I removed the DataTemplateSelector code and simply defined the datatemplates and used:
<ContentPresenter Name="cpDisplay" Content="{Binding}" />

Resources