WPF and MVVM: How use attached properties in my UserControl - c#

Lately ive been trying to make a grid that uses my UserControls to fill it in.
The only problem i've encountered is that I cant use the WPF Binding stuff to link the user controls to my grid, making it for me very hard to nicely place them in the grid.
My question: How can i bind the attributes in my ViewModel (which are stored in the Block class, which my ViewModel has an object of), to my UserControl Block, allowing it to use those variables (the X and Y, which are the row and column of the grid, position)?
Here is the code of my user control:
namespace Mortal_Pets.Views
public partial class BlockView : UserControl
{
public BlockView()
{
InitializeComponent();
DataContext = new BlockViewModel();
}
}
<UserControl x:Class="Mortal_Pets.Views.BlockView"
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="30" d:DesignWidth="30">
<Canvas Background="{Binding Block.Color}" Grid.Row="{Binding Path=Block.XPosition}" Grid.Column="{Binding Path=Block.YPosition}">
</Canvas>
Here is the ViewModel and Model class of the UserControl:
class BlockViewModel
{
public Block Block { get; set; }
public BlockViewModel()
{
Block = new Block();
Block.XPosition = 5; //Does Not Work, But this is how i'd like to have it
Block.YPosition = 5; //Does Not Work, But this is how i'd like to have it
Block.Color = new SolidColorBrush(Colors.Black);
}
}
class Block
{
public int XPosition { get; set; }
public int YPosition { get; set; }
public Brush Color { get; set; }
public Block()
{
}
}
Then following up we have my Window:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BlockView view = new BlockView();
view.SetValue(Grid.ColumnProperty, 5); //This does work, but is ugly and not really usefull for what i intend to do with it
view.SetValue(Grid.RowProperty, 5); //This does work, but is ugly and not really usefull for what i intend to do with it
BoardGrid.Children.Add(view); //This does work, but is ugly and not really usefull for what i intend to do with it
}
}
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Mortal_Pets.Views" x:Class="Mortal_Pets.Views.MainWindow"
Title="MainWindow" Height="700" Width="600"
Loaded="Window_Loaded">
<Grid x:Name="BoardGrid" Margin="10,50,10,10" Width="500" Height="500">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
</Grid.ColumnDefinitions>
<Label x:Name="ComboCounter" Content="{Binding Game.ComboCounter}" HorizontalAlignment="Left" Margin="-2,-61,0,0" VerticalAlignment="Top" Width="95" Grid.ColumnSpan="4"/>
</Grid>
Thanks in advance,
Nick van der Meij

Got it to work based on knowledge found here and here. It is not pretty but this seems to be the only way it will work.
You did not share the MainViewModel (I guess because it was not necessary for the quick sample you gave). But since I needed it for binding and you will most probably work with it, here is my quick version:
class MainViewModel
{
public List<BlockViewModel> Blocks { get; set; }
public MainViewModel()
{
Blocks = new List<BlockViewModel> { new BlockViewModel() };
}
}
You need to wrap the grid in an ItemsControl and use the ItemContainerStyle for binding the Grid.Column and Grid.Row:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="700" Width="600"
xmlns:local="clr-namespace:WpfApplication1">
<ItemsControl ItemsSource="{Binding Path=Blocks}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding Block.YPosition}" />
<Setter Property="Grid.Column" Value="{Binding Block.XPosition}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:BlockView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Margin="10,50,10,10" Width="500" Height="500" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="25"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Window>
The BlockView now looks like this:
<UserControl x:Class="WpfApplication1.BlockView"
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="30" d:DesignWidth="30">
<Canvas Background="{Binding Block.Color}">
</Canvas>
</UserControl>

Related

Popup rendering a black box instead of expected outcome

I have the following code to pop up a form:
<Window x:Class="PoolBet.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:PoolBet"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="TogglePopupButton" Height="30" Width="150" HorizontalAlignment="Left">
<StackPanel>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">
<Run Text="Is button toggled? " />
<Run Text="{Binding IsChecked, ElementName=TogglePopupButton}" />
</TextBlock>
<Popup Name="myPopup" IsOpen="{Binding IsChecked, ElementName=TogglePopupButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<!-- Added after TheGeneral's comment -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Margin="0,10,0,0">Name:</Label>
<TextBox Grid.Column="1" Margin="0,10,0,10" x:Name="nameInput" />
<Label Grid.Row="1">Amount:</Label>
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" x:Name="amountInput" />
<Label Grid.Row="2">Notes:</Label>
<TextBox Grid.Row="2" Grid.Column="1" AcceptsReturn="True" x:Name="notesInput" />
<Button Click="submit" Grid.Row="3" Grid.Column="1" Content="Submit"/>
</Grid>
</Popup>
</StackPanel>
</ToggleButton>
<ItemsControl Name="icTodoList" Grid.Row="5" Grid.Column="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<RadioButton Content="{Binding Choice}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ListView Margin="10" Name="lvUsers" Grid.Column="2" >
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Amount" Width="70" DisplayMemberBinding="{Binding Amount}" />
<GridViewColumn Header="Notes" Width="150" DisplayMemberBinding="{Binding Notes}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
(This is my Code-Behind, not sure if it matters though)
namespace PoolBet
{
public partial class MainWindow : Window
{
public ObservableCollection<User> Users { get; set; } = new ObservableCollection<User>();
public ObservableCollection<Choice> Choices { get; set; } = new ObservableCollection<Choice>();
public MainWindow()
{
InitializeComponent();
lvUsers.ItemsSource = Users;
}
private void submit(object sender, RoutedEventArgs e)
{
Users.Add(new User() { Name = nameInput.Text, Amount = Convert.ToInt32(amountInput.Text), Notes = notesInput.Text });
}
public class User
{
public string Name { get; set; }
public int Amount { get; set; }
public string Notes { get; set; }
}
public class Choice
{
public string ChoiceName { get; set; }
public ObservableCollection<User> Users { get; set; }
}
}
}
I want it to show a form with 3 fields (Name, Amount, Notes) but all I get is a black box and a fragment of the text fields, and the submit button.
I only started C# in earnest 2 days ago and I have no idea what went wrong. Can someone explain it please?
The popup with the grid color set to aqua:
The notes textfield was blocked: Added a new <RowDefinition Height="Auto" /> and that seemed to fix it, although it is still cut in half.
Transparency of the Popup (the Popup child host to be precise) is disabled by default, therefore the content of the Popup is renderd with a black background.
You must explicitely allow transparency on the Popup by setting Popup.AllowsTransparency property to true:
<Popup AllowsTransparency="True" />

TextBlock binding updates only once at the beginning

I have a texblock in my .xaml file that I have binded to a property. There are also 2 buttons to ++ and -- the value of that property when they are clicked. The problem is that the binding works only at the start of the application.
When the button is clicked the corresponding command is executed and variable changes its value in the code (so there is no problem with executing the given methods).
However no changes are visible in the UI. I am not sure what might be the cause here, is the UI being somehow blocked? I have always worked using MVVM way and never have had a problem like that with binding.
If more code is needed let me know, didn't want to put a huge wall of code here.
Constructor:
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Zoom = 60;
ZoomPlusSceneCommand = new RelayCommand(ZoomPlus);
ZoomMinusSceneCommand = new RelayCommand(ZoomMinus);
}
Handling property changed:
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Property itself:
private int zoom;
public int Zoom
{
get { return zoom; }
set { if (zoom != value) { zoom = value; RaisePropertyChanged("Zoom"); } }
}
Commands:
public RelayCommand ZoomPlusSceneCommand { get; set; }
public RelayCommand ZoomMinusSceneCommand { get; set; }
where RelayCommand is an implementation that I use as a template in most of my projects and they've always been working well (at least in MVVM projects)
Methods executed with the usage of commands when a button is clicked:
private void ZoomPlus(object o)
{
Zoom++;
}
private void ZoomMinus(object o)
{
Zoom--;
}
Xaml:
<Window x:Class="Rendering3D.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:Rendering3D"
Loaded="GetSceneSize"
ResizeMode="NoResize"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="900">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition x:Name="SceneColumn" Width="*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition x:Name="SceneRow" Height="*"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Image x:Name="SceneImage" Grid.Column="1" Grid.Row="1"
PreviewMouseLeftButtonDown="SceneMouseLeftButtonDown"
MouseMove="SceneMouseMove"
MouseWheel="SceneMouseWheel"/>
<Grid Grid.Column="3" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Padding" Value="0 5 0 5"/>
</Style>
</Grid.Resources>
<Button Grid.Row="0" Content="+" Command="{Binding ZoomPlusSceneCommand}"/>
<Button Grid.Row="2" Content="-" Command="{Binding ZoomMinusSceneCommand}"/>
<Label Grid.Row="4" Content="Zoom" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="5" Text="{Binding Zoom}" HorizontalAlignment="Center"/>
</Grid>
</Grid>
Example of a mouse event:
private void SceneMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
Zoom++;
else
Zoom--;
return;
}
Assuming the property gets set, the view should be updated provided that your MainWindow class actually implements INotifyPropertyChanged:
public partial class MainWindow : Window, INotifyPropertyChanged
...

Setting position of ItemsControl item

I have a command in my viewmodel that, when executed, will add an item to an observablecollection. In my view, an ItemsControl has its source bound to this collection. So whenever an item is added, a combobox and a textblock will appear for each item.
What I'm trying to do is, have each set of combobox/textblock appear to the right of the last set, until it reaches the end of window, and then the next set will appear below the first, and so on. Was planning to put this in a ScrollViewer. Everything I've tried so far keeps placing each set under the last one, instead of to the right.
Here's my simple model class:
public class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double _gridColumn;
public double GridColumn
{
get { return _gridColumn; }
set { _gridColumn = value; OnPropertyChanged("GridColumn"); }
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Here's the relevant parts of the viewmodel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private int columnNum = 0;
private ObservableCollection<DataModel> _dataModelCollection = new ObservableCollection<DataModel>();
public ObservableCollection<DataModel> DataModelCollection
{
get { return _dataModelCollection; }
set { _dataModelCollection = value; OnPropertyChanged("DataModelCollection"); }
}
public void AddDataModel(object parameter)
{
DataModelCollection.Add(new DataModel {GridColumn = columnNum % 8 });
columnNum += 2;
}
}
And now my view:
<Grid Background="#44D3D3D3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140*" />
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="140*" />
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="140*" />
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="140*" />
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="140*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="46*" />
<RowDefinition Height="139*" />
<RowDefinition Height="38*" />
<RowDefinition Height="78*" />
<RowDefinition Height="60*" />
<RowDefinition Height="50*" />
</Grid.RowDefinitions>
<Button Grid.Row="3"
Grid.Column="2"
Content="Add Set"
Command="{Binding AddDataModelCmd}"/>
<ItemsControl Grid.Row="4"
Grid.RowSpan="2"
Grid.ColumnSpan="9"
ItemsSource="{Binding DataModelCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Grid.Column="{Binding GridColumn}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140*" />
<ColumnDefinition Width="7*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="7" />
<RowDefinition Height="53" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<ComboBox Grid.Column="0" Grid.Row="1" />
<TextBlock Text="tester"
Grid.Column="0"
Grid.Row="2"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
I've messed around with setting the ItemsPanelTemplate as a WrapPanel which gave me the side by side result, but I couldn't get any spacing between each set of items.

Use data template based on property

Is it possible to control which DataTemplate a node used based on a property rather than the class type which is typically seen in wpf.
In my case I have a list of teams and I want to control the background of each team being listed in the listbox as well as a few other design elements such as displaying different logos based on which team. In my mind it seems easiest to just make a data template based on the team name.
How do you guys suggest I handle it. I don't want to create a class object for every entire team. However it would be ideal if a team doesn't have a design template that a default one gets used.
Either way if someone could put together a super simple example Id appreciate it considering im not sure how to do it .
From what you described, it seems to me that those property can be hold on the Team class and you could display the content based on them !, but since you might need something much complicated you could use a DataTemplateSelector basically what you need to do is :
First : In resources area define the DataTemplates that you need plus a default one, in case none of the teams names matche a difined template,
lets say something like that :
<Window.Resources>
<DataTemplate x:Key="DefaultnDataTemplate" DataType="{x:Type YourNameSpace:Team}">
<Grid Background="LightGreen">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="DefaultnDataTemplate"/>
<TextBlock Text="{Binding Id}" Grid.Row="1" Grid.Column="0"/>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" Grid.Row="1" Grid.Column="1"/>
<TextBlock Text="{Binding Matches}" Grid.Row="1" Grid.Column="2"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="TeamADataTemplate" DataType="{x:Type YourNameSpace:Team}">
<Grid Background="LightCoral">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="TeamADataTemplate"/>
<TextBlock Text="{Binding Id}" Grid.Row="1" Grid.Column="0"/>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" Grid.Row="1" Grid.Column="1"/>
<TextBlock Text="{Binding Matches}" Grid.Row="1" Grid.Column="2"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="TeamBDataTemplate" DataType="{x:Type YourNameSpace:Team}">
<Grid Background="LightBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="TeamBDataTemplate"/>
<TextBlock Text="{Binding Id}" Grid.Row="1" Grid.Column="0"/>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Center" Grid.Row="1" Grid.Column="1"/>
<TextBlock Text="{Binding Matches}" Grid.Row="1" Grid.Column="2"/>
</Grid>
</DataTemplate>
</Window.Resources>
Second add a DataTemplateSelector class, the class will basically check the team name and return the appropriate DataTemplate:
public class TeamDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultnDataTemplate { get; set; }
public DataTemplate TeamADataTemplate { get; set; }
public DataTemplate TeamBDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
var teamName = (item as Team).Name;
switch (teamName)
{
case "TeamA":
return TeamADataTemplate;
case "TeamB":
return TeamBDataTemplate;
default:
return DefaultnDataTemplate;
}
}
}
Third, add an instance of that class to the StaticResources, and point it to the already defined DataTemplates :
<YourNameSpace:TeamDataTemplateSelector x:Key="TeamDataTemplateSelector" TeamADataTemplate="{StaticResource TeamADataTemplate}" TeamBDataTemplate="{StaticResource TeamBDataTemplate}" DefaultnDataTemplate="{StaticResource DefaultnDataTemplate}"/>
Finally call the TemplateSelector in your List:
<ListBox ItemsSource="{Binding Teams}" ItemTemplateSelector="{StaticResource TeamDataTemplateSelector}">
</ListBox>
here the model i am using in this sample :
public class Team
{
public string Name { get; set; }
public string Id { get; set; }
public string Matches { get; set; }
}
private ObservableCollection<Team> _teams=new ObservableCollection<Team>()
{
new Team()
{
Id="1",
Matches = "45",
Name = "TeamA"
},
new Team()
{
Id="1",
Matches = "45",
Name = "TeamB"
},
new Team()
{
Id="1",
Matches = "45",
Name = "TeamC"
}
};
public ObservableCollection<Team> Teams
{
get
{
return _teams;
}
set
{
if (_teams == value)
{
return;
}
_teams = value;
OnPropertyChanged();
}
}

The name TemplateSelector does not exist in the namespace

I get this error:
Error 1 The name "TemplateSelector" does not exist in the namespace "using:MyApps"
but I don't know why because when I create new project and paste the same code to him everything is working so problem is only in my old project. I also try clean or rebuild project 100 times and manually delete bin folder but still not work.
<Page
x:Class="MyApps.BlankPage1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApps"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
...
<UserControl>
<UserControl.Resources>
<!-- Template for INCOMNIG messages -->
<DataTemplate x:Key="IncomnigTemplate">
<Grid>
<Grid Margin="27,0,0,0" HorizontalAlignment="Left" Background="#BFE8FF" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding MessengerMessage}" HorizontalAlignment="Left" Margin="5,5,20,0" VerticalAlignment="Top" Foreground="black"></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding MessengerTime}" HorizontalAlignment="Left" Margin="5,0,0,5" VerticalAlignment="Bottom" FontSize="9" Foreground="#908C8C"></TextBlock>
</Grid>
</Grid>
</DataTemplate>
<!-- Template for OUTGOING messages -->
<DataTemplate x:Key="OutgoinTemplate">
<Grid>
<Grid Margin="27,0,0,0" HorizontalAlignment="Right" Background="Gray" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding MessengerMessage}" HorizontalAlignment="Left" Margin="5,5,20,0" VerticalAlignment="Top" Foreground="black"></TextBlock>
<TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding MessengerTime}" HorizontalAlignment="Left" Margin="5,0,0,5" VerticalAlignment="Bottom" FontSize="9" Foreground="#908C8C"></TextBlock>
</Grid>
</Grid>
</DataTemplate>
<!-- datatemplate selector -->
<local:TemplateSelector x:Key="MessageTemplateSelector"
EmptyTemplate="{x:Null}"
IncomingMessageTemplate="{StaticResource IncomnigTemplate}"
OutgoingMessageCaptureTemplate="{StaticResource OutgoinTemplate}"/>
</UserControl.Resources>
<ListBox ItemTemplateSelector="{StaticResource MessageTemplateSelector}" x:Name="lbChoosenMessagesUsers" Grid.Column="3" FontSize="13" ItemsSource="{Binding MyDatasCurentUser}" Margin="0,0,50,0">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</UserControl>
Class TeplateSelector inside project:
public class TemplateSelector : DataTemplateSelector
{
public DataTemplate IncomingMessageTemplate { get; set; }
public DataTemplate OutgoingMessageCaptureTemplate { get; set; }
public DataTemplate EmptyTemplate { get; set; }
public new DataTemplate SelectTemplate(object item, DependencyObject container)
{
var x = item as Message;
if (x != null)
{
return null;
}
return EmptyTemplate;
}
}
I've often got problem like this too. My solution is simple: just close all opened XAML files, and then build the project again. It works for me.

Categories

Resources