I'm crap atn english, so sorry..
I'm trying to create dynamic menu items that display something based on a collection (a list of object), here is my xaml, you can see the "ListBox" and the "MenuItem".
As I said, I'm binding the header to the "name" of my object :
MainWindow.xaml
<Grid Margin="0,0,-8,-9" Background="Black" >
<DockPanel x:Name="LayoutRoot">
<Grid VerticalAlignment="Top">
<MediaElement x:Name="mediaElement" HorizontalAlignment="Center" Margin="0,0,60,30" VerticalAlignment="Top" MouseLeftButtonUp="mediaElement_MouseLeftButtonUp">
</MediaElement>
<Menu HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="525" IsMainMenu="True">
<MenuItem Header="Menu">
<ListBox x:Name="myList" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="461,-261,-1,106" Background="#FFFFE800" MouseDoubleClick="ListBox_Double_Click" Width="57">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<MenuItem Header="{Binding name}"> </MenuItem>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</MenuItem>
</Menu>
</Grid>
Here is my code in the c#, as you can see I bind "myList" (which is my ListBox) with the ItemsGetSource of list (which contains the things I want to display in my menu):
public MainWindow()
{
var list = new List<History>
{
new History() { name = "Guy1"},
new History() { name = "Guy2"},
new History() { name = "Guy3"},
new History() { name = "Guy4"},
};
InitializeComponent();
this.myList.ItemsSource = list;
}
And my class "History" (the "name" field is what I want to display)
namespace MediaPlayer
{
public class History
{
// "prop" puis "tab"
public String name { get; set; }
public String path { get; set; }
public int time { get; set; }
public override string ToString()
{
return name;
}
}
}
I think I can't use itemSource for my menuItems, maybe?
Here is an example that only uses MenuItems:
MainWindow.xaml
<Grid Margin="0,0,-8,-9" Background="Black" >
<DockPanel x:Name="LayoutRoot">
<Grid VerticalAlignment="Top">
<MediaElement x:Name="mediaElement" HorizontalAlignment="Center" Margin="0,0,60,30" VerticalAlignment="Top" MouseLeftButtonUp="mediaElement_MouseLeftButtonUp">
</MediaElement>
<Menu HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="525" IsMainMenu="True">
<MenuItem Header="Menu" x:Name="myList">
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Header" Value="{Binding name}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</Menu>
</Grid>
</DockPanel>
</Grid>
The result looks like this:
Related
So I have an application that's setup like this.
my MainView.xaml
<ItemsControl ItemsSource="{Binding CardViewModel.Users}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultEffectDataTemplate="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserCard/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the ViewModel
class BaseViewModel : ObservableObject
{
public CardViewModel CardViewModel { get; set; } = new CardViewModel();
}
This works fine it displays two UserCards which is my UserControl in the ItemsControl which is exactly what it should be doing and it also binds the Text properties to what it needs to.
<Grid Style="{StaticResource UserCardStyle}">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit"/>
<MenuItem Header="Remove"
Command="{Binding BaseViewModel.CardViewModel.command}"/>
</ContextMenu>
</Grid.ContextMenu>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Width="75"
HorizontalAlignment="Left"
Column="0">
<Ellipse Width="50"
Height="50"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="10">
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding Avatar}"/>
</Ellipse.Fill>
</Ellipse>
</Grid>
<Grid Column="1">
<TextBlock Text="{Binding Description}"
TextWrapping="Wrap"
Width="180"
VerticalAlignment="Top"
Margin="10"
FontFamily="Consolas"/>
<TextBlock Width="100"
Height="20"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="5"
Text="{Binding Name}"
FontFamily="Consolas"/>
<TextBlock Width="100"
Height="20"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
Text="{Binding Id}"
FontFamily="Consolas"/>
</Grid>
</Grid>
However I wanted to add a DataContext as you can see at the top but I have no idea how to bind the DataContext of the UserControl to something else so that I can create commands for the ContextMenu MenuItems
I did setup a RelayCommand that works on the ViewModel because I have the DataContext set properly there.
Right now the UserCard datacontext inherits from it's parent in the MainWindow view which makes it to where the DataContext for the properties are all from User
public class User : ObservableObject
{
public ImageSource Avatar { get; set; }
public string Description { get; set; }
public int Id { get; set; }
}
I want to be able to either create a ViewModel for that specific control and add commands to that or so that I can bind it to the CardViewModel and still display the data from the Users collection
public CardViewModel()
{
/*
* Commands
*/
command = new RelayCommand(o => LoadImage(), o => true);
AddUser = new RelayCommand(u => DisplayUserBuilder(), u => true);
Users = new ObservableCollection<User>();
Users.Add(new User
{
Name = "User",
Description = "A description",
Id = 0
});
Users.Add(new User
{
Name = "User1",
Description = "Super nice description",
Id = 1
});
If I set the DataContext in the CodeBehind like this, the command works fine but then I can't see any text
public partial class UserCard : UserControl
{
public UserCard()
{
InitializeComponent();
this.DataContext = new BaseViewModel();
}
}
I believe you need something like this :
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit"/>
<MenuItem Header="Remove"
Command="{Binding DataContext.CardViewModel.command, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type MainView}}"/>
</ContextMenu>
</Grid.ContextMenu>
This is what I ended up doing, adding a reference to the ViewModel and then setting it.
<Grid.ContextMenu>
<ContextMenu >
<ContextMenu.DataContext>
<dad:BaseViewModel/>
</ContextMenu.DataContext>
<MenuItem Header="Edit"/>
<MenuItem Header="Remove"
Command="{Binding CardViewModel.command}"/>
</ContextMenu>
</Grid.ContextMenu>
If someone knows a "better" or "cleaner" way of doing the same thing please let me know since I am trying to develop as a developer, no pun intended.
I am very new to MVVM and I am stuck with data binding. I have a button on my view page which dynamically creates text boxes but I cannot see how I bind these textboxes to my List in ViewModel.
In my view i have:
<Button x:Name="btWebsite" Grid.ColumnSpan="2" Width="50" Height="50" Click="btWebsite_Click" Margin="23,245,259,202">
<StackPanel x:Name="pnWebsiteButton" Orientation="Horizontal">
<Image x:Name="imgWebsite" Source= "Images/webIcon.jpg" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</StackPanel>
</Button>
<GroupBox x:Name="grpWebsite" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="73,245,0,0" Grid.ColumnSpan="2" Height="51" Width="170" BorderBrush="{x:Null}" BorderThickness="0">
<ScrollViewer x:Name="pnScrollWebsite" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0,0,0,-6">
<StackPanel x:Name="pnWebsite" Orientation="Vertical" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="1,2,0,0" VerticalAlignment="Top" IsEnabled="True">
</StackPanel>
</ScrollViewer>
</GroupBox>
The code behind the button is:
private void btWebsite_Click(object sender, RoutedEventArgs e)
{
var newTextBox = new TextBox();
newTextBox.Text = "type the website address...";
newTextBox.Foreground = Brushes.Gray;
newTextBox.Width = 150;
newTextBox.Name = "txtWebsite" + iWebsites;
pnWebsite.Children.Add(newTextBox);
pnWebsite.RegisterName(newTextBox.Name, newTextBox);
iWebsites++;
}
In my ViewModel i have:
public List<string> Websites
{
get { return _websites; }
set
{
if (value != _websites)
{
_websites = value;
OnPropertyChanged("Websites");
}
}
}
I am struggling to see how I get the website textboxes into the viewmodel list. Thank you for your help
Delete your event handler from the code-behind: btWebsite_Click.
Modify your xaml like this:
<Button x:Name="btWebsite" Grid.ColumnSpan="2" Width="50" Height="50" Command="{Binding AddNewStringCommand}" Margin="23,245,259,202">
<StackPanel x:Name="pnWebsiteButton" Orientation="Horizontal">
<Image x:Name="imgWebsite" Source= "Images/webIcon.jpg" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</StackPanel>
</Button>
<GroupBox x:Name="grpWebsite" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="73,245,0,0" Grid.ColumnSpan="2" Height="51" Width="170" BorderBrush="{x:Null}" BorderThickness="0">
<ScrollViewer x:Name="pnScrollWebsite" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0,0,0,-6">
<StackPanel x:Name="pnWebsite" Orientation="Vertical" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="1,2,0,0" VerticalAlignment="Top" IsEnabled="True">
<ItemsControl ItemsSource="{Binding Websites}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Mode=TwoWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</GroupBox>
You need to modify your ViewModel also:
public ObservableCollection<string> Websites { get; set; }
public ICommand AddNewStringCommand => new RelayCommand(AddNewString);
private void AddNewString()
{
Websites.Add(string.Empty);
}
Instead of RelayCommand you can use any implementation of ICommand. I use for example MVVMLight.
As you see, the main differences:
Instead of handling the Click event, there is a Command Binding in
the button.
Instead of generating new controls from code behind, there is an
ItemsControl that creates one every time when we have a new
element in the collection.
The new TextBox's Text property is bound to the new element.
Update:
I made a mistake, ObservableCollection is not working directly with the TextBox.
It seems you need something in addition:
public class Website
{
public string Name { get; set; }
}
Modify the ViewModel like this:
public ObservableCollection<Website> Websites { get; set; } = new ObservableCollection<Website>();
public ICommand AddNewStringCommand => new RelayCommand(AddNewString);
private void AddNewString()
{
Websites.Add(new Website {Name = "new website"});
}
And the ItemsTemplate like this:
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel >
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
I have a ListView with a DataTemplate, inside this templates there are several textblocks and a button. The button has a contextmenu with fixed items. The binding of the listviewitems works fine, but binding a property to the contextmenu does not seem to work.
<ListView x:Name="lv_clients" Margin="0 22 0 0" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid Grid.Column="0" Grid.RowSpan="2" Background="{Binding StateColor}">
</Grid>
<TextBlock Grid.Column="1" Text="{Binding DisplayString}" Foreground="Black" Height="20" FontWeight="Bold" Padding="2,2,0,0" />
<Button Click="Button_ListItem_Click" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Anrufen" Name="mn_call" Click="mn_call_Click" DataContext={Binding Number} />
</ContextMenu>
</Button.ContextMenu> ...</Button>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBlock Text="{Binding State}" Height="20" Padding="2,2,0,0"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstEntry.KDKGRS}" Height="20" FontWeight="Bold" Padding="2,2,2,0" HorizontalAlignment="Left" Foreground="{Binding FirstEntry.ConvertedKGFARBE}" />
<TextBlock Text="{Binding FirstEntry.ADNAMI}" Height="20" Padding="0,2,0,0" HorizontalAlignment="Left" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have removed some unnecessary bits of the code (style and columndefinitions) for readability.
The important part is the MenuItem inside the Button. My underlying class has a public string property Number. This should be passed to the menu item. But the DataContext of the MenuItem is always null inside the click event.
I've read something about the contextmenu not beeing part of the visual tree, but I can't wrap my head around it. Could somebody explain the issue with the binding?
Edit Code for the underlying class:
Again removed some unnecessary code for the question
public class PhoneClient
{
public String Name { get; set; }
public String Number { get; set; }
public String Extension { get; set; }
public String DisplayString
{
get
{
return String.IsNullOrEmpty(Name) ? Number : String.Format("{0} ({1})", Name, Extension);
}
}
}
And the binding of the ListBox:
List<PhoneClient> clients = new List<PhoneClient>();
clients = load(); //returns active Clients
lv_clients.ItemsSource = clients;
Bridging the gap
<ContextMenu Tag="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Anrufen" Click="mn_call_Click" Name="mn_call"
DataContext="{Binding Tag.Number, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
Handler
private void mn_call_Click(object sender, RoutedEventArgs e)
{
MenuItem currentMenuItem = (MenuItem)sender;
string number = (string)currentMenuItem.DataContext;
// Do Stuff
}
EDIT
MainWindow.xaml
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Margin="10">
<ListView x:Name="lv_clients" Margin="0 22 0 0" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="LightGray" Width="100">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Background="LightGreen">
</Grid>
<TextBlock Text="{Binding DisplayString}" Foreground="Black" Height="20" FontWeight="Bold" Padding="2,2,0,0" />
<Button Click="Button_ListItem_Click" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button.ContextMenu>
<ContextMenu Tag="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Show" Click="mn_call_Click" Name="mn_call" DataContext="{Binding Tag.Number, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
</Button.ContextMenu> ...
</Button>
<StackPanel Grid.Row="1">
<TextBlock Text="{Binding State}" Height="20" Padding="2,2,0,0"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Foo" Height="20" FontWeight="Bold" Padding="2,2,2,0" HorizontalAlignment="Left" Foreground="Blue" />
<TextBlock Text="Bar" Height="20" Padding="0,2,0,0" HorizontalAlignment="Left" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;
namespace WpfApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<PhoneClient> clients = new List<PhoneClient>();
clients.Add(new PhoneClient() { Name = "Kumar", Number = "0101010", Extension = "555", State = "New York" });
clients.Add(new PhoneClient() { Name = "Shanaya", Number = "1010101", Extension = "555", State = "New Jersey" });
clients.Add(new PhoneClient() { Name = "Billy Bob", Number = "6543210", Extension = "555", State = "Single" });
lv_clients.ItemsSource = clients;
}
public class PhoneClient
{
public String Name { get; set; }
public String Number { get; set; }
public String Extension { get; set; }
public String State { get; set; }
public String DisplayString
{
get
{
return String.IsNullOrEmpty(Name) ? Number : String.Format("{0} ({1})", Name, Extension);
}
}
}
private void mn_call_Click(object sender, RoutedEventArgs e)
{
MenuItem currentMenuItem = (MenuItem)sender;
string number = (string)currentMenuItem.DataContext;
MessageBox.Show("Number " + number);
}
private void Button_ListItem_Click(object sender, RoutedEventArgs e)
{
Button currentButton = (Button)sender;
PhoneClient data = (PhoneClient)currentButton.DataContext;
MessageBox.Show(data.Name + " tapped");
}
}
}
In my application I have a window which contain a ListBox, and controls that should show different properties of its currently selected item. Those controls are:
TextBox that should show 'Name' property.
TextBox that should show 'DataFile` property.
DataGrid that should show 'TItems property, which is an ObservableCollection.
I tried to bind SelectedItem to an object, and then bind different properties of that object to the controls mentioned above, with no success.
The window:
My View:
<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:local="clr-namespace:ReportMaker"
xmlns:ViewModel="clr-namespace:ReportMaker.ViewModel" x:Class="ReportMaker.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<ViewModel:MainViewModel/>
</Window.DataContext>
<Grid>
<Button x:Name="button" Content="Create" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75"/>
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="120"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Margin="10,10,0,36.667" Width="119" ItemsSource="{Binding ReportItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel HorizontalAlignment="Left" Height="274" Margin="134,10,0,0" VerticalAlignment="Top" Width="375" DataContext="{Binding SelectedReportItem}">
<StackPanel.Resources>
<Style x:Key="ControlBaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="0, 10, 0, 0" />
</Style>
</StackPanel.Resources>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBox Width="150" Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data File:"/>
<TextBox Width="150" Text="{Binding ID}"/>
</StackPanel>
<DataGrid Height="190" VerticalAlignment="Bottom" ItemsSource="{Binding TItems}"/>
</StackPanel>
<Button x:Name="button_Copy" Content="Save" HorizontalAlignment="Right" Margin="0,0,92,10" VerticalAlignment="Bottom" Width="75"/>
</Grid>
</Window>
My ViewModel:
public class MainViewModel
{
public ObservableCollection<ReportItem> ReportItems { get; set; }
public object SelectedReportItem { get; set; }
public MainViewModel()
{
ReportItems = new ObservableCollection<ReportItem>();
ReportItems.Add(Example);
}
public ReportItem Example = new TextReportItem() { Name = "John", DataFile = "try.txt"};
}
ReportItem:
public class ReportItem
{
public int Id { get; set; }
public string Name { get; set; }
public string DataFile { get; set; }
}
TextReportItem:
public class TextReportItem : ReportItem
{
public ObservableCollection<TextParcel> TItems { get; set; }
}
public class TextParcel
{
char Delimiter { get; set; }
string LineExp { get; set; }
string Result { get; set; }
string IgnoreLine { get; set; }
int DesiredResultIndexInLine { get; set; }
}
EDIT: as I use MVVM, I prefer to use only XAML in the View, with no code behind.
EDIT 2:
Thanks to S.Akbari I succeeded to view the desired properties in the TextBox controls, with the following code:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBox Width="150" Text="{Binding ElementName=listBox, Path=SelectedItem.Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data File:"/>
<TextBox Width="150" Text="{Binding ElementName=listBox, Path=SelectedItem.DataFile}"/>
</StackPanel>
But when the same logic is applied to my DataGrid, it fails for some reason:
<DataGrid Height="190" VerticalAlignment="Bottom" ItemsSource="{Binding ElementName=listBox, Path=SelectedItem.TItmes}" />
I also tried:
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}" ItemsSource="{Binding TItems}"/>
And also:
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}">
<DataTemplate>
<TextBlock Text="{Binding TItems}" />
</DataTemplate>
</DataGrid>
if you use MVVM your view model should raise property changed events
You should implement INotifyPropertyChanged
and change the selected item to be a full property
see :How to: Implement Property Change Notification
Hi im having an issue where a null Reference exception is being thrown in my xaml for a user control using a data template selector and I'm honestly not sure why. Here is the code below and any help would be appreciated.
UPDATE it only happens at design time not at run time
Data Template Selector code:
using System.Windows;
using System.Windows.Controls;
using UI.ViewModel;
namespace UI.DataTemplateSelectors
{
public class CouponViewerDataTemplateSelector : DataTemplateSelector
{
public DataTemplate coupon1DataTemplateSelector { get; set; }
public DataTemplate coupon2DataTemplateSelector { get; set; }
public DataTemplate coupon3DataTemplateSelector { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null)
return null;
var CouponViewerViewModel = (CouponViewerViewModel)item;
switch (CouponViewerViewModel.Coupon.CouponBarcode )
{
case "994460":
return Coupon1DataTemplateSelector;
case "994470":
return Coupon2DataTemplateSelector;
case "994480":
return Coupon3DataTemplateSelector;
}
return null;
}
}
}
The Xaml (I have collapsed the different DataTemplates code as the xaml file is massive)
<UserControl x:Class="UI.View.CouponViewerView"
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:viewModel="clr-namespace:UI.ViewModel"
xmlns:converter="clr-namespace:UI.View.Converter"
xmlns:converters="clr-namespace:UI.Converters"
xmlns:Web="clr-namespace:Web;assembly=Web"
xmlns:dataTemplateSelectors="clr-namespace:UI.DataTemplateSelectors"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=viewModel:CouponViewerViewModel, IsDesignTimeCreatable=True}"
Height="1018" Width="720">
<UserControl.Resources>
<converter:EmptyStringToVisibilityConverter x:Key="EmptyStringToVisibilityConverter"/>
<converters:AppendCharToBeginningAndEndOfStringConverter x:Key="AppendCharToBeginningAndEndOfStringConverter"/>
<converters:HexToBackgroundColourConverter x:Key="HexToBackgroundColourConverter"/>
<converters:HexToForegroundColourConverter x:Key="HexToForegroundColourConverter"/>
<converters:MaxCharcterSelectionNameConverter x:Key="MaxCharcterSelectionNameConverter"/>
<converters:DateTimeToSplitDataGridConverter x:Key="DateTimeToSplitDataGridConverter"/>
<converters:HeaderFormatterConverter x:Key="HeaderFormatterConverter"/>
<DataTemplate x:Key="Coupon1DataTemplateSelector" ...>
<DataTemplate x:Key="Coupon2DataTemplateSelector" ...>
<DataTemplate x:Key="Coupon3DataTemplateSelector" ...>
<dataTemplateSelectors:CouponViewerDataTemplateSelector
Coupon1DataTemplateSelector="{StaticResource Coupon1DataTemplateSelector}"
Coupon2DataTemplateSelector="{StaticResource Coupon2DataTemplateSelector}"
Coupon3DataTemplateSelector ="{StaticResource Coupon3DataTemplateSelector}"
x:Key="CouponViewerDataTemplateSelector" />
</UserControl.Resources>
<StackPanel>
<StackPanel x:Name="StackPanelToPrint">
<StackPanel.ContextMenu >
<ContextMenu>
<MenuItem Header="Print" Click="PrintCurrentForm" />
<MenuItem Header="OverLay Image" Command="{Binding Path=OverlayImageToCouponViewerCommand }" />
</ContextMenu>
</StackPanel.ContextMenu>
<Grid Margin="0,0,0,0">
<TextBlock Text="{Binding DesignTimeError}" Visibility="{Binding DesignTimeError, Converter={StaticResource EmptyStringToVisibilityConverter}}" Grid.ColumnSpan="2" Margin="0,0,0,34" />
<Canvas Grid.ColumnSpan="2" Margin="0,0,0,0">
<Rectangle Fill="Black" Width="8.5" Height="8.5" Canvas.Left="11" Canvas.Top="128" />
<Rectangle Fill="Black" Width="8.5" Height="8.5" Canvas.Left="742.5" Canvas.Top="128" />
<TextBlock Canvas.Left="338" FontSize="9" Foreground="Red" Canvas.Top="1046" Text="{Binding Path=MarkSenseCoupon.CouponBarcode}" />
<TextBlock FontFamily="Free 3 Of 9" Canvas.Left="24" Canvas.Top="1026" FontSize="110" Height="15" Text="{Binding Path=Coupon.CouponBarcode, Converter={StaticResource AppendCharToBeginningAndEndOfStringConverter}}"/>
<TextBlock Canvas.Left="409" FontSize="9" Foreground="Red" Canvas.Top="1046" Text="{Binding Path=MarkSenseCoupon.CouponInstance}" />
<TextBlock FontFamily="Free 3 of 9" Canvas.Left="409" Canvas.Top="1026" FontSize="110" Height="15" Text="{Binding Path=Coupon.CouponInstance, Converter={StaticResource AppendCharToBeginningAndEndOfStringConverter}}"/>
<Rectangle Fill="Black" Width="8.5" Height="8.5" Canvas.Left="11.5" Canvas.Top="1043" />
<Rectangle Fill="Black" Width="8.5" Height="8.5" Canvas.Left="742.5" Canvas.Top="1043" />
</Canvas>
<Image Canvas.ZIndex="1" Source="{Binding Coupon.OverlayImage}" Margin="0,-21,-76,108" Stretch="Fill" x:Name="PrintImageContextMenu" />
<StackPanel Margin="-105,146,66,0" Height="900" VerticalAlignment="Top" >
<ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource CouponViewerDataTemplateSelector}" />
</StackPanel>
</Grid>
</StackPanel>
</StackPanel>
</UserControl>
Stack Trace:
at UI.DataTemplateSelectors.CouponViewerDataTemplateSelector.SelectTemplate(Object item, DependencyObject container)
at System.Windows.Controls.ContentPresenter.ChooseTemplate()
at System.Windows.Controls.ContentPresenter.EnsureTemplate()
at System.Windows.Controls.ContentPresenter.OnPreApplyTemplate()
at System.Windows.FrameworkElement.ApplyTemplate()
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.UIElement.UpdateLayout()
My Colleague who had been working on this before me had added this line of code to the ViewModel without me noticing and this caused all the issues due to it returning before design time data had been loaded
public CouponViewerViewModel()
{
if (DesignerProperties.IsInDesignMode == true)
{
return;
}
if (DesignerProperties.IsInDesignMode)
{
LoadDesignTimeData();
}
}
Apologies for a silly question in the end
Property names are case sensitive.
public DataTemplate coupon1DataTemplateSelector { get; set; }
vs.
Coupon1DataTemplateSelector="{StaticResource Coupon1DataTemplateSelector}"