How to properly bind multiple ViewModels when using DataTemplateSelector [duplicate]
This question already has an answer here:
How to use DataTemplateSelector with ContentControl to display different controls based on the view-model?
2 answers
I'm trying to write a simple dialog that would accept a value in a SpinEdit or a text in a TextEdit. I'm using multiple VMs and I made a selector that should view a proper control based on the logic in the c++/cli file.
XAML:
xmlns:local="clr-namespace:asd"
Title="Binding Path=Title, Mode=OneTime"
<dx:DXWindow.Resources>
<DataTemplate x:Key="TInputValueVM" DataType="x:Type local:TInputValueVM">
<dxe:SpinEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength" />
</DataTemplate>
<DataTemplate x:Key="TInputTextVM" DataType="x:Type local:TInputTextVM">
<dxe:TextEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
MaskType="RegEx" Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength"/>
</DataTemplate>
<local:PropertyDataTemplateSelector x:Key="templateSelector"
DataTemplate_Value="StaticResource TInputValueVM"
DataTemplate_Text="StaticResource TInputTextVM" />
</dx:DXWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<Label x:Uid="Label" MinHeight="24" MinWidth="60" Content="Value" />
<ContentControl Content="Binding Path=Whoami" ContentTemplateSelector="StaticResource templateSelector" />
</StackPanel>
<StackPanel Grid.Row="1" x:Uid="OKCancel_Buttons" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button Height="23" x:Name="OK_Button" Click="OK_Click" Content="OK" IsDefault="True" HorizontalAlignment="Right" MinWidth="95" />
<Button Height="23" x:Name="Cancel_Button" Click="Cancel_Click" Content="Cancel" HorizontalAlignment="Right" MinWidth="95" />
</StackPanel>
</Grid>
In c# I have a base VM and two VMS that extend it, one for values and one for text. The rest of the properties stay the same.
C#
namespace asd
public class TInputBaseVM : ViewModelBase
private string m_sTitle;
private string m_sMask;
private int m_nInputLenght;
private string m_sWhoami;
public TInputBaseVM(string A_sTitle, string A_sMask, int A_nInputLength)
m_sTitle = A_sTitle;
m_sMask = A_sMask;
m_nInputLenght = A_nInputLength;
protected string Title
get return m_sTitle;
set SetProperty(ref m_sTitle, value, () => Title);
protected string Mask
get return m_sMask;
set SetProperty(ref m_sMask, value, () => Mask);
protected int InputLength
get return m_nInputLenght;
set SetProperty(ref m_nInputLenght, value, () => InputLength);
protected string Whoami
get return m_sWhoami;
set SetProperty(ref m_sWhoami, value, () => Whoami);
public class TInputValueVM : TInputBaseVM
public TInputValueVM(string A_sTitle, string A_sMask, int A_nInputLength, double A_nValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_nValue;
Whoami = "Value";
private double m_nValue;
public double Value
get return m_nValue;
set SetProperty(ref m_nValue, value, () => Value);
public class TInputTextVM : TInputBaseVM
public TInputTextVM(string A_sTitle, string A_sMask, int A_nInputLength, string A_sValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_sValue;
Whoami = "Text";
private string m_sValue;
public string Value
get return m_sValue;
set SetProperty(ref m_sValue, value, () => Value);
public class PropertyDataTemplateSelector : DataTemplateSelector
public DataTemplate DataTemplate_Value get; set;
public DataTemplate DataTemplate_Text get; set;
public override DataTemplate SelectTemplate(object item, DependencyObject container)
var selector = item as string;
if(selector == "Value")
return DataTemplate_Value;
return DataTemplate_Text;
In c++/cli I create an object of a proper VM and I'd like the WPF to automatically update the view to either spinedit or textedit, however I'm not sure how to properly bind the properties from the C#. If I explicitly type 'Value' in the Content property of the ContentControl then it displays the spinEdit but I don't know how to bind it so it automatically takes the correct property.
EDIT: I'm adding c++/cli code to show how I choose different VMs
C++/cli:
bool TSignalNumberPositionDialogCLR::StartDialog(TSignalNumberPositionSupport& A_Attributes, HWND A_hwndParent, LPTSTR String)
try
TInputValueVM ^oExchange_Value;
TInputTextVM ^oExchange_Text;
int inputFormat = A_Attributes.GetInputFormat();
if(inputFormat)
oExchange_Text = gcnew TInputTextVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), gcnew System::String(A_Attributes.GetInitialText()));
else
oExchange_Value = gcnew TInputValueVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), A_Attributes.GetInitialValue());
Dialogs::TSignalNumberPositionDialog^ dialog = gcnew Dialogs::TSignalNumberPositionDialog();
if(inputFormat)
dialog->DataContext = oExchange_Text;
else
dialog->DataContext = oExchange_Value;
dialog->ShowDialog();
if(dialog->DialogResult)
CString nValue;
if(inputFormat)
nValue = oExchange_Text->Value;
else
nValue = ((Decimal)oExchange_Value->Value).ToString("F2", CultureInfo::InvariantCulture);
A_Attributes.UpdateValue(nValue, String, A_Attributes.GetInputLength());
return true;
return false;
catch(Exception^ e)
e;
based on the 'inputFormat' variable I want to display different controls in the dialog.
EDIT: Based on @Clemens comments I got rid of the selector sectionand the x:Key property in the DataTemplates. I changed the content opf the Content property to Content="Binding" and it somehow works. The moment I create a VM it selects the correct one.
c# wpf c++-cli
marked as duplicate by Clemens
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Nov 13 '18 at 11:27
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
|
show 3 more comments
This question already has an answer here:
How to use DataTemplateSelector with ContentControl to display different controls based on the view-model?
2 answers
I'm trying to write a simple dialog that would accept a value in a SpinEdit or a text in a TextEdit. I'm using multiple VMs and I made a selector that should view a proper control based on the logic in the c++/cli file.
XAML:
xmlns:local="clr-namespace:asd"
Title="Binding Path=Title, Mode=OneTime"
<dx:DXWindow.Resources>
<DataTemplate x:Key="TInputValueVM" DataType="x:Type local:TInputValueVM">
<dxe:SpinEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength" />
</DataTemplate>
<DataTemplate x:Key="TInputTextVM" DataType="x:Type local:TInputTextVM">
<dxe:TextEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
MaskType="RegEx" Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength"/>
</DataTemplate>
<local:PropertyDataTemplateSelector x:Key="templateSelector"
DataTemplate_Value="StaticResource TInputValueVM"
DataTemplate_Text="StaticResource TInputTextVM" />
</dx:DXWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<Label x:Uid="Label" MinHeight="24" MinWidth="60" Content="Value" />
<ContentControl Content="Binding Path=Whoami" ContentTemplateSelector="StaticResource templateSelector" />
</StackPanel>
<StackPanel Grid.Row="1" x:Uid="OKCancel_Buttons" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button Height="23" x:Name="OK_Button" Click="OK_Click" Content="OK" IsDefault="True" HorizontalAlignment="Right" MinWidth="95" />
<Button Height="23" x:Name="Cancel_Button" Click="Cancel_Click" Content="Cancel" HorizontalAlignment="Right" MinWidth="95" />
</StackPanel>
</Grid>
In c# I have a base VM and two VMS that extend it, one for values and one for text. The rest of the properties stay the same.
C#
namespace asd
public class TInputBaseVM : ViewModelBase
private string m_sTitle;
private string m_sMask;
private int m_nInputLenght;
private string m_sWhoami;
public TInputBaseVM(string A_sTitle, string A_sMask, int A_nInputLength)
m_sTitle = A_sTitle;
m_sMask = A_sMask;
m_nInputLenght = A_nInputLength;
protected string Title
get return m_sTitle;
set SetProperty(ref m_sTitle, value, () => Title);
protected string Mask
get return m_sMask;
set SetProperty(ref m_sMask, value, () => Mask);
protected int InputLength
get return m_nInputLenght;
set SetProperty(ref m_nInputLenght, value, () => InputLength);
protected string Whoami
get return m_sWhoami;
set SetProperty(ref m_sWhoami, value, () => Whoami);
public class TInputValueVM : TInputBaseVM
public TInputValueVM(string A_sTitle, string A_sMask, int A_nInputLength, double A_nValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_nValue;
Whoami = "Value";
private double m_nValue;
public double Value
get return m_nValue;
set SetProperty(ref m_nValue, value, () => Value);
public class TInputTextVM : TInputBaseVM
public TInputTextVM(string A_sTitle, string A_sMask, int A_nInputLength, string A_sValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_sValue;
Whoami = "Text";
private string m_sValue;
public string Value
get return m_sValue;
set SetProperty(ref m_sValue, value, () => Value);
public class PropertyDataTemplateSelector : DataTemplateSelector
public DataTemplate DataTemplate_Value get; set;
public DataTemplate DataTemplate_Text get; set;
public override DataTemplate SelectTemplate(object item, DependencyObject container)
var selector = item as string;
if(selector == "Value")
return DataTemplate_Value;
return DataTemplate_Text;
In c++/cli I create an object of a proper VM and I'd like the WPF to automatically update the view to either spinedit or textedit, however I'm not sure how to properly bind the properties from the C#. If I explicitly type 'Value' in the Content property of the ContentControl then it displays the spinEdit but I don't know how to bind it so it automatically takes the correct property.
EDIT: I'm adding c++/cli code to show how I choose different VMs
C++/cli:
bool TSignalNumberPositionDialogCLR::StartDialog(TSignalNumberPositionSupport& A_Attributes, HWND A_hwndParent, LPTSTR String)
try
TInputValueVM ^oExchange_Value;
TInputTextVM ^oExchange_Text;
int inputFormat = A_Attributes.GetInputFormat();
if(inputFormat)
oExchange_Text = gcnew TInputTextVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), gcnew System::String(A_Attributes.GetInitialText()));
else
oExchange_Value = gcnew TInputValueVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), A_Attributes.GetInitialValue());
Dialogs::TSignalNumberPositionDialog^ dialog = gcnew Dialogs::TSignalNumberPositionDialog();
if(inputFormat)
dialog->DataContext = oExchange_Text;
else
dialog->DataContext = oExchange_Value;
dialog->ShowDialog();
if(dialog->DialogResult)
CString nValue;
if(inputFormat)
nValue = oExchange_Text->Value;
else
nValue = ((Decimal)oExchange_Value->Value).ToString("F2", CultureInfo::InvariantCulture);
A_Attributes.UpdateValue(nValue, String, A_Attributes.GetInputLength());
return true;
return false;
catch(Exception^ e)
e;
based on the 'inputFormat' variable I want to display different controls in the dialog.
EDIT: Based on @Clemens comments I got rid of the selector sectionand the x:Key property in the DataTemplates. I changed the content opf the Content property to Content="Binding" and it somehow works. The moment I create a VM it selects the correct one.
c# wpf c++-cli
marked as duplicate by Clemens
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Nov 13 '18 at 11:27
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Content="Binding Path=Whoami"
and the ContentTemplateSelector don't seem to make sense. When you assign or bind an object to the Content property of a ContentControl, the control automatically select an appropriate ContentTemplate via the DataTemplate's DataType, i.e. one that matches the Content type.
– Clemens
Nov 13 '18 at 9:35
@Clemens So what would I need to do? delete the whole selector section and bind what exactly in the Content property or ContentControl?
– bananeeek
Nov 13 '18 at 9:52
As said, the ContentTemplate is automatically selected according to the type of the Content. If you bind Content to an object of typeMyClass
, the DataTemplate withDataType"x:Type local:MyClass"
and without ax:Key
is chosen.
– Clemens
Nov 13 '18 at 10:05
@Clemens But I have two VMs and two DataTemplates. If I define one DT as DataType"x:Type local:TInputValueVM" and the second DT as DataType"(x:Type local:TInputTextVM}" then what do I bind the ControlContent's Content property to?
– bananeeek
Nov 13 '18 at 10:16
The appropriate view model, for example a property CurrentVM likeContent="Binding CurrentVM"
. CurrentVM returns either a TInputValueVM or a TInputTextVM.
– Clemens
Nov 13 '18 at 10:29
|
show 3 more comments
This question already has an answer here:
How to use DataTemplateSelector with ContentControl to display different controls based on the view-model?
2 answers
I'm trying to write a simple dialog that would accept a value in a SpinEdit or a text in a TextEdit. I'm using multiple VMs and I made a selector that should view a proper control based on the logic in the c++/cli file.
XAML:
xmlns:local="clr-namespace:asd"
Title="Binding Path=Title, Mode=OneTime"
<dx:DXWindow.Resources>
<DataTemplate x:Key="TInputValueVM" DataType="x:Type local:TInputValueVM">
<dxe:SpinEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength" />
</DataTemplate>
<DataTemplate x:Key="TInputTextVM" DataType="x:Type local:TInputTextVM">
<dxe:TextEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
MaskType="RegEx" Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength"/>
</DataTemplate>
<local:PropertyDataTemplateSelector x:Key="templateSelector"
DataTemplate_Value="StaticResource TInputValueVM"
DataTemplate_Text="StaticResource TInputTextVM" />
</dx:DXWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<Label x:Uid="Label" MinHeight="24" MinWidth="60" Content="Value" />
<ContentControl Content="Binding Path=Whoami" ContentTemplateSelector="StaticResource templateSelector" />
</StackPanel>
<StackPanel Grid.Row="1" x:Uid="OKCancel_Buttons" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button Height="23" x:Name="OK_Button" Click="OK_Click" Content="OK" IsDefault="True" HorizontalAlignment="Right" MinWidth="95" />
<Button Height="23" x:Name="Cancel_Button" Click="Cancel_Click" Content="Cancel" HorizontalAlignment="Right" MinWidth="95" />
</StackPanel>
</Grid>
In c# I have a base VM and two VMS that extend it, one for values and one for text. The rest of the properties stay the same.
C#
namespace asd
public class TInputBaseVM : ViewModelBase
private string m_sTitle;
private string m_sMask;
private int m_nInputLenght;
private string m_sWhoami;
public TInputBaseVM(string A_sTitle, string A_sMask, int A_nInputLength)
m_sTitle = A_sTitle;
m_sMask = A_sMask;
m_nInputLenght = A_nInputLength;
protected string Title
get return m_sTitle;
set SetProperty(ref m_sTitle, value, () => Title);
protected string Mask
get return m_sMask;
set SetProperty(ref m_sMask, value, () => Mask);
protected int InputLength
get return m_nInputLenght;
set SetProperty(ref m_nInputLenght, value, () => InputLength);
protected string Whoami
get return m_sWhoami;
set SetProperty(ref m_sWhoami, value, () => Whoami);
public class TInputValueVM : TInputBaseVM
public TInputValueVM(string A_sTitle, string A_sMask, int A_nInputLength, double A_nValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_nValue;
Whoami = "Value";
private double m_nValue;
public double Value
get return m_nValue;
set SetProperty(ref m_nValue, value, () => Value);
public class TInputTextVM : TInputBaseVM
public TInputTextVM(string A_sTitle, string A_sMask, int A_nInputLength, string A_sValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_sValue;
Whoami = "Text";
private string m_sValue;
public string Value
get return m_sValue;
set SetProperty(ref m_sValue, value, () => Value);
public class PropertyDataTemplateSelector : DataTemplateSelector
public DataTemplate DataTemplate_Value get; set;
public DataTemplate DataTemplate_Text get; set;
public override DataTemplate SelectTemplate(object item, DependencyObject container)
var selector = item as string;
if(selector == "Value")
return DataTemplate_Value;
return DataTemplate_Text;
In c++/cli I create an object of a proper VM and I'd like the WPF to automatically update the view to either spinedit or textedit, however I'm not sure how to properly bind the properties from the C#. If I explicitly type 'Value' in the Content property of the ContentControl then it displays the spinEdit but I don't know how to bind it so it automatically takes the correct property.
EDIT: I'm adding c++/cli code to show how I choose different VMs
C++/cli:
bool TSignalNumberPositionDialogCLR::StartDialog(TSignalNumberPositionSupport& A_Attributes, HWND A_hwndParent, LPTSTR String)
try
TInputValueVM ^oExchange_Value;
TInputTextVM ^oExchange_Text;
int inputFormat = A_Attributes.GetInputFormat();
if(inputFormat)
oExchange_Text = gcnew TInputTextVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), gcnew System::String(A_Attributes.GetInitialText()));
else
oExchange_Value = gcnew TInputValueVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), A_Attributes.GetInitialValue());
Dialogs::TSignalNumberPositionDialog^ dialog = gcnew Dialogs::TSignalNumberPositionDialog();
if(inputFormat)
dialog->DataContext = oExchange_Text;
else
dialog->DataContext = oExchange_Value;
dialog->ShowDialog();
if(dialog->DialogResult)
CString nValue;
if(inputFormat)
nValue = oExchange_Text->Value;
else
nValue = ((Decimal)oExchange_Value->Value).ToString("F2", CultureInfo::InvariantCulture);
A_Attributes.UpdateValue(nValue, String, A_Attributes.GetInputLength());
return true;
return false;
catch(Exception^ e)
e;
based on the 'inputFormat' variable I want to display different controls in the dialog.
EDIT: Based on @Clemens comments I got rid of the selector sectionand the x:Key property in the DataTemplates. I changed the content opf the Content property to Content="Binding" and it somehow works. The moment I create a VM it selects the correct one.
c# wpf c++-cli
This question already has an answer here:
How to use DataTemplateSelector with ContentControl to display different controls based on the view-model?
2 answers
I'm trying to write a simple dialog that would accept a value in a SpinEdit or a text in a TextEdit. I'm using multiple VMs and I made a selector that should view a proper control based on the logic in the c++/cli file.
XAML:
xmlns:local="clr-namespace:asd"
Title="Binding Path=Title, Mode=OneTime"
<dx:DXWindow.Resources>
<DataTemplate x:Key="TInputValueVM" DataType="x:Type local:TInputValueVM">
<dxe:SpinEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength" />
</DataTemplate>
<DataTemplate x:Key="TInputTextVM" DataType="x:Type local:TInputTextVM">
<dxe:TextEdit Height="23" Width="200"
Text="Binding Value, Mode=TwoWay"
MaskType="RegEx" Mask="Binding Mask, Mode=OneWay"
MaxLength="Binding Path=InputLength"/>
</DataTemplate>
<local:PropertyDataTemplateSelector x:Key="templateSelector"
DataTemplate_Value="StaticResource TInputValueVM"
DataTemplate_Text="StaticResource TInputTextVM" />
</dx:DXWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<Label x:Uid="Label" MinHeight="24" MinWidth="60" Content="Value" />
<ContentControl Content="Binding Path=Whoami" ContentTemplateSelector="StaticResource templateSelector" />
</StackPanel>
<StackPanel Grid.Row="1" x:Uid="OKCancel_Buttons" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Button Height="23" x:Name="OK_Button" Click="OK_Click" Content="OK" IsDefault="True" HorizontalAlignment="Right" MinWidth="95" />
<Button Height="23" x:Name="Cancel_Button" Click="Cancel_Click" Content="Cancel" HorizontalAlignment="Right" MinWidth="95" />
</StackPanel>
</Grid>
In c# I have a base VM and two VMS that extend it, one for values and one for text. The rest of the properties stay the same.
C#
namespace asd
public class TInputBaseVM : ViewModelBase
private string m_sTitle;
private string m_sMask;
private int m_nInputLenght;
private string m_sWhoami;
public TInputBaseVM(string A_sTitle, string A_sMask, int A_nInputLength)
m_sTitle = A_sTitle;
m_sMask = A_sMask;
m_nInputLenght = A_nInputLength;
protected string Title
get return m_sTitle;
set SetProperty(ref m_sTitle, value, () => Title);
protected string Mask
get return m_sMask;
set SetProperty(ref m_sMask, value, () => Mask);
protected int InputLength
get return m_nInputLenght;
set SetProperty(ref m_nInputLenght, value, () => InputLength);
protected string Whoami
get return m_sWhoami;
set SetProperty(ref m_sWhoami, value, () => Whoami);
public class TInputValueVM : TInputBaseVM
public TInputValueVM(string A_sTitle, string A_sMask, int A_nInputLength, double A_nValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_nValue;
Whoami = "Value";
private double m_nValue;
public double Value
get return m_nValue;
set SetProperty(ref m_nValue, value, () => Value);
public class TInputTextVM : TInputBaseVM
public TInputTextVM(string A_sTitle, string A_sMask, int A_nInputLength, string A_sValue) : base(A_sTitle, A_sMask, A_nInputLength)
Value = A_sValue;
Whoami = "Text";
private string m_sValue;
public string Value
get return m_sValue;
set SetProperty(ref m_sValue, value, () => Value);
public class PropertyDataTemplateSelector : DataTemplateSelector
public DataTemplate DataTemplate_Value get; set;
public DataTemplate DataTemplate_Text get; set;
public override DataTemplate SelectTemplate(object item, DependencyObject container)
var selector = item as string;
if(selector == "Value")
return DataTemplate_Value;
return DataTemplate_Text;
In c++/cli I create an object of a proper VM and I'd like the WPF to automatically update the view to either spinedit or textedit, however I'm not sure how to properly bind the properties from the C#. If I explicitly type 'Value' in the Content property of the ContentControl then it displays the spinEdit but I don't know how to bind it so it automatically takes the correct property.
EDIT: I'm adding c++/cli code to show how I choose different VMs
C++/cli:
bool TSignalNumberPositionDialogCLR::StartDialog(TSignalNumberPositionSupport& A_Attributes, HWND A_hwndParent, LPTSTR String)
try
TInputValueVM ^oExchange_Value;
TInputTextVM ^oExchange_Text;
int inputFormat = A_Attributes.GetInputFormat();
if(inputFormat)
oExchange_Text = gcnew TInputTextVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), gcnew System::String(A_Attributes.GetInitialText()));
else
oExchange_Value = gcnew TInputValueVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
A_Attributes.GetInputLength(), A_Attributes.GetInitialValue());
Dialogs::TSignalNumberPositionDialog^ dialog = gcnew Dialogs::TSignalNumberPositionDialog();
if(inputFormat)
dialog->DataContext = oExchange_Text;
else
dialog->DataContext = oExchange_Value;
dialog->ShowDialog();
if(dialog->DialogResult)
CString nValue;
if(inputFormat)
nValue = oExchange_Text->Value;
else
nValue = ((Decimal)oExchange_Value->Value).ToString("F2", CultureInfo::InvariantCulture);
A_Attributes.UpdateValue(nValue, String, A_Attributes.GetInputLength());
return true;
return false;
catch(Exception^ e)
e;
based on the 'inputFormat' variable I want to display different controls in the dialog.
EDIT: Based on @Clemens comments I got rid of the selector sectionand the x:Key property in the DataTemplates. I changed the content opf the Content property to Content="Binding" and it somehow works. The moment I create a VM it selects the correct one.
This question already has an answer here:
How to use DataTemplateSelector with ContentControl to display different controls based on the view-model?
2 answers
c# wpf c++-cli
c# wpf c++-cli
edited Nov 13 '18 at 10:36
bananeeek
asked Nov 13 '18 at 7:28
bananeeekbananeeek
2317
2317
marked as duplicate by Clemens
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Nov 13 '18 at 11:27
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by Clemens
StackExchange.ready(function()
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function()
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function()
$hover.showInfoMessage('',
messageElement: $msg.clone().show(),
transient: false,
position: my: 'bottom left', at: 'top center', offsetTop: -7 ,
dismissable: false,
relativeToBody: true
);
,
function()
StackExchange.helpers.removeMessages();
);
);
);
Nov 13 '18 at 11:27
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
Content="Binding Path=Whoami"
and the ContentTemplateSelector don't seem to make sense. When you assign or bind an object to the Content property of a ContentControl, the control automatically select an appropriate ContentTemplate via the DataTemplate's DataType, i.e. one that matches the Content type.
– Clemens
Nov 13 '18 at 9:35
@Clemens So what would I need to do? delete the whole selector section and bind what exactly in the Content property or ContentControl?
– bananeeek
Nov 13 '18 at 9:52
As said, the ContentTemplate is automatically selected according to the type of the Content. If you bind Content to an object of typeMyClass
, the DataTemplate withDataType"x:Type local:MyClass"
and without ax:Key
is chosen.
– Clemens
Nov 13 '18 at 10:05
@Clemens But I have two VMs and two DataTemplates. If I define one DT as DataType"x:Type local:TInputValueVM" and the second DT as DataType"(x:Type local:TInputTextVM}" then what do I bind the ControlContent's Content property to?
– bananeeek
Nov 13 '18 at 10:16
The appropriate view model, for example a property CurrentVM likeContent="Binding CurrentVM"
. CurrentVM returns either a TInputValueVM or a TInputTextVM.
– Clemens
Nov 13 '18 at 10:29
|
show 3 more comments
Content="Binding Path=Whoami"
and the ContentTemplateSelector don't seem to make sense. When you assign or bind an object to the Content property of a ContentControl, the control automatically select an appropriate ContentTemplate via the DataTemplate's DataType, i.e. one that matches the Content type.
– Clemens
Nov 13 '18 at 9:35
@Clemens So what would I need to do? delete the whole selector section and bind what exactly in the Content property or ContentControl?
– bananeeek
Nov 13 '18 at 9:52
As said, the ContentTemplate is automatically selected according to the type of the Content. If you bind Content to an object of typeMyClass
, the DataTemplate withDataType"x:Type local:MyClass"
and without ax:Key
is chosen.
– Clemens
Nov 13 '18 at 10:05
@Clemens But I have two VMs and two DataTemplates. If I define one DT as DataType"x:Type local:TInputValueVM" and the second DT as DataType"(x:Type local:TInputTextVM}" then what do I bind the ControlContent's Content property to?
– bananeeek
Nov 13 '18 at 10:16
The appropriate view model, for example a property CurrentVM likeContent="Binding CurrentVM"
. CurrentVM returns either a TInputValueVM or a TInputTextVM.
– Clemens
Nov 13 '18 at 10:29
Content="Binding Path=Whoami"
and the ContentTemplateSelector don't seem to make sense. When you assign or bind an object to the Content property of a ContentControl, the control automatically select an appropriate ContentTemplate via the DataTemplate's DataType, i.e. one that matches the Content type.– Clemens
Nov 13 '18 at 9:35
Content="Binding Path=Whoami"
and the ContentTemplateSelector don't seem to make sense. When you assign or bind an object to the Content property of a ContentControl, the control automatically select an appropriate ContentTemplate via the DataTemplate's DataType, i.e. one that matches the Content type.– Clemens
Nov 13 '18 at 9:35
@Clemens So what would I need to do? delete the whole selector section and bind what exactly in the Content property or ContentControl?
– bananeeek
Nov 13 '18 at 9:52
@Clemens So what would I need to do? delete the whole selector section and bind what exactly in the Content property or ContentControl?
– bananeeek
Nov 13 '18 at 9:52
As said, the ContentTemplate is automatically selected according to the type of the Content. If you bind Content to an object of type
MyClass
, the DataTemplate with DataType"x:Type local:MyClass"
and without a x:Key
is chosen.– Clemens
Nov 13 '18 at 10:05
As said, the ContentTemplate is automatically selected according to the type of the Content. If you bind Content to an object of type
MyClass
, the DataTemplate with DataType"x:Type local:MyClass"
and without a x:Key
is chosen.– Clemens
Nov 13 '18 at 10:05
@Clemens But I have two VMs and two DataTemplates. If I define one DT as DataType"x:Type local:TInputValueVM" and the second DT as DataType"(x:Type local:TInputTextVM}" then what do I bind the ControlContent's Content property to?
– bananeeek
Nov 13 '18 at 10:16
@Clemens But I have two VMs and two DataTemplates. If I define one DT as DataType"x:Type local:TInputValueVM" and the second DT as DataType"(x:Type local:TInputTextVM}" then what do I bind the ControlContent's Content property to?
– bananeeek
Nov 13 '18 at 10:16
The appropriate view model, for example a property CurrentVM like
Content="Binding CurrentVM"
. CurrentVM returns either a TInputValueVM or a TInputTextVM.– Clemens
Nov 13 '18 at 10:29
The appropriate view model, for example a property CurrentVM like
Content="Binding CurrentVM"
. CurrentVM returns either a TInputValueVM or a TInputTextVM.– Clemens
Nov 13 '18 at 10:29
|
show 3 more comments
1 Answer
1
active
oldest
votes
Based on your comment. Let me improve my answer. As you are facing issue in VM selection. so plesae concentrate how I assigned VM to datatemplate. Although it is done in very basic way, you can handle it if you you are using MVVM packages.
I have created 2 data template and 2 vms and each vm is bound to datatemplate. To verify, I have a combobox, which will select datatemplate based on selected value.
Here is Sample VM
public class VM : System.ComponentModel.INotifyPropertyChanged
private string title;
private SolidColorBrush background;
public string Title get => title; set title = value; RaisePropertyChanged();
public SolidColorBrush Background get => background; set background = value; RaisePropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public class VM1: VM
public VM1()
Title = "This is VM1";
Background = Brushes.Yellow;
public class VM2: VM
public VM2()
Title = "This is VM2";
Background = Brushes.Orange;
Now check for resources
<local:VM1 x:Key="VM1"/>
<local:VM2 x:Key="VM2"/>
<DataTemplate x:Key="DT1">
<Grid DataContext="StaticResource VM1">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DT2">
<Grid DataContext="StaticResource VM2">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<Style TargetType="ContentControl" x:Key="contentStyle">
<Style.Triggers>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template1">
<Setter Property="ContentTemplate" Value="StaticResource DT1" />
</DataTrigger>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template2">
<Setter Property="ContentTemplate" Value="StaticResource DT2" />
</DataTrigger>
</Style.Triggers>
</Style>
and finally I have combobox and content control just to verify
<ComboBox Name="cmbo"/>
<ContentControl Style="StaticResource contentStyle"/>
where cmbo.ItemsSource = new List "Template1", "Template2" ;
Hope you got the point
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
1
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Based on your comment. Let me improve my answer. As you are facing issue in VM selection. so plesae concentrate how I assigned VM to datatemplate. Although it is done in very basic way, you can handle it if you you are using MVVM packages.
I have created 2 data template and 2 vms and each vm is bound to datatemplate. To verify, I have a combobox, which will select datatemplate based on selected value.
Here is Sample VM
public class VM : System.ComponentModel.INotifyPropertyChanged
private string title;
private SolidColorBrush background;
public string Title get => title; set title = value; RaisePropertyChanged();
public SolidColorBrush Background get => background; set background = value; RaisePropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public class VM1: VM
public VM1()
Title = "This is VM1";
Background = Brushes.Yellow;
public class VM2: VM
public VM2()
Title = "This is VM2";
Background = Brushes.Orange;
Now check for resources
<local:VM1 x:Key="VM1"/>
<local:VM2 x:Key="VM2"/>
<DataTemplate x:Key="DT1">
<Grid DataContext="StaticResource VM1">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DT2">
<Grid DataContext="StaticResource VM2">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<Style TargetType="ContentControl" x:Key="contentStyle">
<Style.Triggers>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template1">
<Setter Property="ContentTemplate" Value="StaticResource DT1" />
</DataTrigger>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template2">
<Setter Property="ContentTemplate" Value="StaticResource DT2" />
</DataTrigger>
</Style.Triggers>
</Style>
and finally I have combobox and content control just to verify
<ComboBox Name="cmbo"/>
<ContentControl Style="StaticResource contentStyle"/>
where cmbo.ItemsSource = new List "Template1", "Template2" ;
Hope you got the point
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
1
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
add a comment |
Based on your comment. Let me improve my answer. As you are facing issue in VM selection. so plesae concentrate how I assigned VM to datatemplate. Although it is done in very basic way, you can handle it if you you are using MVVM packages.
I have created 2 data template and 2 vms and each vm is bound to datatemplate. To verify, I have a combobox, which will select datatemplate based on selected value.
Here is Sample VM
public class VM : System.ComponentModel.INotifyPropertyChanged
private string title;
private SolidColorBrush background;
public string Title get => title; set title = value; RaisePropertyChanged();
public SolidColorBrush Background get => background; set background = value; RaisePropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public class VM1: VM
public VM1()
Title = "This is VM1";
Background = Brushes.Yellow;
public class VM2: VM
public VM2()
Title = "This is VM2";
Background = Brushes.Orange;
Now check for resources
<local:VM1 x:Key="VM1"/>
<local:VM2 x:Key="VM2"/>
<DataTemplate x:Key="DT1">
<Grid DataContext="StaticResource VM1">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DT2">
<Grid DataContext="StaticResource VM2">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<Style TargetType="ContentControl" x:Key="contentStyle">
<Style.Triggers>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template1">
<Setter Property="ContentTemplate" Value="StaticResource DT1" />
</DataTrigger>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template2">
<Setter Property="ContentTemplate" Value="StaticResource DT2" />
</DataTrigger>
</Style.Triggers>
</Style>
and finally I have combobox and content control just to verify
<ComboBox Name="cmbo"/>
<ContentControl Style="StaticResource contentStyle"/>
where cmbo.ItemsSource = new List "Template1", "Template2" ;
Hope you got the point
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
1
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
add a comment |
Based on your comment. Let me improve my answer. As you are facing issue in VM selection. so plesae concentrate how I assigned VM to datatemplate. Although it is done in very basic way, you can handle it if you you are using MVVM packages.
I have created 2 data template and 2 vms and each vm is bound to datatemplate. To verify, I have a combobox, which will select datatemplate based on selected value.
Here is Sample VM
public class VM : System.ComponentModel.INotifyPropertyChanged
private string title;
private SolidColorBrush background;
public string Title get => title; set title = value; RaisePropertyChanged();
public SolidColorBrush Background get => background; set background = value; RaisePropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public class VM1: VM
public VM1()
Title = "This is VM1";
Background = Brushes.Yellow;
public class VM2: VM
public VM2()
Title = "This is VM2";
Background = Brushes.Orange;
Now check for resources
<local:VM1 x:Key="VM1"/>
<local:VM2 x:Key="VM2"/>
<DataTemplate x:Key="DT1">
<Grid DataContext="StaticResource VM1">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DT2">
<Grid DataContext="StaticResource VM2">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<Style TargetType="ContentControl" x:Key="contentStyle">
<Style.Triggers>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template1">
<Setter Property="ContentTemplate" Value="StaticResource DT1" />
</DataTrigger>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template2">
<Setter Property="ContentTemplate" Value="StaticResource DT2" />
</DataTrigger>
</Style.Triggers>
</Style>
and finally I have combobox and content control just to verify
<ComboBox Name="cmbo"/>
<ContentControl Style="StaticResource contentStyle"/>
where cmbo.ItemsSource = new List "Template1", "Template2" ;
Hope you got the point
Based on your comment. Let me improve my answer. As you are facing issue in VM selection. so plesae concentrate how I assigned VM to datatemplate. Although it is done in very basic way, you can handle it if you you are using MVVM packages.
I have created 2 data template and 2 vms and each vm is bound to datatemplate. To verify, I have a combobox, which will select datatemplate based on selected value.
Here is Sample VM
public class VM : System.ComponentModel.INotifyPropertyChanged
private string title;
private SolidColorBrush background;
public string Title get => title; set title = value; RaisePropertyChanged();
public SolidColorBrush Background get => background; set background = value; RaisePropertyChanged();
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = "")
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public class VM1: VM
public VM1()
Title = "This is VM1";
Background = Brushes.Yellow;
public class VM2: VM
public VM2()
Title = "This is VM2";
Background = Brushes.Orange;
Now check for resources
<local:VM1 x:Key="VM1"/>
<local:VM2 x:Key="VM2"/>
<DataTemplate x:Key="DT1">
<Grid DataContext="StaticResource VM1">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DT2">
<Grid DataContext="StaticResource VM2">
<TextBlock Text="Binding Title" Background="Binding Background"/>
</Grid>
</DataTemplate>
<Style TargetType="ContentControl" x:Key="contentStyle">
<Style.Triggers>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template1">
<Setter Property="ContentTemplate" Value="StaticResource DT1" />
</DataTrigger>
<DataTrigger Binding="Binding ElementName=cmbo, Path=SelectedValue" Value="Template2">
<Setter Property="ContentTemplate" Value="StaticResource DT2" />
</DataTrigger>
</Style.Triggers>
</Style>
and finally I have combobox and content control just to verify
<ComboBox Name="cmbo"/>
<ContentControl Style="StaticResource contentStyle"/>
where cmbo.ItemsSource = new List "Template1", "Template2" ;
Hope you got the point
edited Nov 13 '18 at 9:16
answered Nov 13 '18 at 8:23
Kamran AsimKamran Asim
48426
48426
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
1
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
add a comment |
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
1
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
Do I define that in the xaml? I have added this.DataContext = this; In the code behind right where I initialize the component, but I'm not sure how to make a VM a current one. EDIT: Or do I define that datacontext = viewmodel in the selector?
– bananeeek
Nov 13 '18 at 8:37
1
1
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
I improved the answer, please go through
– Kamran Asim
Nov 13 '18 at 9:17
add a comment |
Content="Binding Path=Whoami"
and the ContentTemplateSelector don't seem to make sense. When you assign or bind an object to the Content property of a ContentControl, the control automatically select an appropriate ContentTemplate via the DataTemplate's DataType, i.e. one that matches the Content type.– Clemens
Nov 13 '18 at 9:35
@Clemens So what would I need to do? delete the whole selector section and bind what exactly in the Content property or ContentControl?
– bananeeek
Nov 13 '18 at 9:52
As said, the ContentTemplate is automatically selected according to the type of the Content. If you bind Content to an object of type
MyClass
, the DataTemplate withDataType"x:Type local:MyClass"
and without ax:Key
is chosen.– Clemens
Nov 13 '18 at 10:05
@Clemens But I have two VMs and two DataTemplates. If I define one DT as DataType"x:Type local:TInputValueVM" and the second DT as DataType"(x:Type local:TInputTextVM}" then what do I bind the ControlContent's Content property to?
– bananeeek
Nov 13 '18 at 10:16
The appropriate view model, for example a property CurrentVM like
Content="Binding CurrentVM"
. CurrentVM returns either a TInputValueVM or a TInputTextVM.– Clemens
Nov 13 '18 at 10:29