WPF, how to destroy and recreate usercontrol based on changes in other, & binding problem
up vote
0
down vote
favorite
I am new to WPF and C#,
I have a main screen consist of multiple user controls and some of the need to be destroyed and recreate on the fly based on the selection of one.
Here is my sample WMMW code,
Models
public class Method : INotifyPropertyChanged, IDataErrorInfo
{
#region properties
private string _method;
private string _helper;
#endregion
public Method()
{
_method = "MM1";
_helper = "HM1";
}
//getter setters..
}
public class Property : INotifyPropertyChanged
{
#region Properties
private string _name;
private string _path;
private float _standarddeviation;
private string _unit;
//getter setters
}
MethodViewModel
class MethodViewModel
{
#region Properties
private Method _method;
#endregion
#region Getter & Setters
public Method Method
{
get { return _method; }
}
public ICommand UpdateCommand
{
get; private set;
}
#endregion
#region Constructor
/// <summary>
/// Initialize a new interface of the MEthodViewModel class
/// </summary>
public MethodViewModel()
{
//test
_method = new Method();
UpdateCommand = new MethodUpdateCommand(this);
}
#endregion
#region Functions
public void SaveChanges()
{
//TODO: Destroy and rebuild the usercontrol
}
#endregion
}
Command
class MethodUpdateCommand : ICommand
{
private MethodViewModel _viewModel;
/// <summary>
/// Initialize a new instance of MethodNameUpdate Command
/// </summary>
/// <param name="viewModel"></param>
public MethodUpdateCommand(MethodViewModel viewModel)
{
_viewModel = viewModel;
}
#region ICOmmand Members
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return String.IsNullOrWhiteSpace(_viewModel.Method.Error);
}
public void Execute(object parameter)
{
_viewModel.SaveChanges();
}
#endregion
}
Main screen
<Window x:Class="WpfApplicationTest.Views.MainScreen"
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:WpfApplicationTest.Views"
xmlns:control="clr-namespace:WpfApplicationTest.Controls"
mc:Ignorable="d"
Title="MainScreen" Height="573.763" Width="354.839">
<Grid Margin="0,0,0,-41">
<control:MethodControl Margin="21,23,63,460" RenderTransformOrigin="0.507,0.567"></control:MethodControl>
<control:PropertyControl Margin="0,129,0,-129"></control:PropertyControl>
</Grid>
Method Control
<UserControl x:Class="WpfApplicationTest.Controls.MethodControl"
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"
xmlns:local="clr-namespace:WpfApplicationTest.Controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d" d:DesignWidth="300" Height="101.075">
<WrapPanel Orientation=" Horizontal" VerticalAlignment="Top" Height="120" >
<Label Content="Method Name:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource MethodNames}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Label Content="Reflection Type:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Helper, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource HelperMethods}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</WrapPanel>
Property control.xaml
<StackPanel Name="Test"></StackPanel>
public partial class PropertyControl : UserControl
{
public PropertyControl()
{
InitializeComponent();
PopulatePropertyPanel("MM1", "HM1");
}
private void PopulatePropertyPanel(string name, string reflection)
{
//TODO: decide which mthod
//int methodindex = Constant.GetMethodNameIndex(name);
int methodindex = Array.IndexOf((String)Application.Current.Resources["MethodNames"], name);
switch (methodindex)
{
case 0:
foreach (String prop in (String)Application.Current.Resources["Result1"])
{
PopulateProperty(prop, true);
}
break;
default:
foreach (String prop in (String)Application.Current.Resources["Result2"])
{
PopulateProperty(prop, false);
}
break;
}
}
private void PopulateProperty(string prop, Boolean constant)
{
Label lbl = new Label();
lbl.Content = prop;
TextBox pathtext = new TextBox();
pathtext.Text = "path";
TextBox std = new TextBox();
std.Text = "std";
TextBox unit = new TextBox();
unit.Text = "unit";
Test.Children.Add(lbl);
Test.Children.Add(pathtext);
Test.Children.Add(std);
Test.Children.Add(unit);
}
}
I want to recreate populate property-control, every time there is a change in method-control, which I already create a command for it.
Also, how can I bind the components in property control with property model,
I need to have a collection of properties (1 property for each result, and destroy and rebuild the collection with property-control.
EDIT 1:
Main window
<ContentControl Grid.Row="1" Content="{Binding ChildViewModel}" />
Resources
<DataTemplate DataType="{x:Type modelViews:PropertyViewModel}">
<control:PropertyControl />
</DataTemplate>
MainViewModel
class MethodViewModel : INotifyPropertyChanged
{
#region Properties
private Method _method;
private PropertyViewModel _childViewModel;
#endregion
#region Getter & Setters
public PropertyViewModel ChildViewModel
{
get { return this._childViewModel; }
set
{
if (this._childViewModel != value)
{
this._childViewModel = value;
OnPropertyChanged("ChildViewModel");
}
}
}
public MethodViewModel()
{
//test
_method = new Method();
_childViewModel = new PropertyViewModel();
_childViewModel.CollectProperties(_method.Name, _method.Helper);
UpdateCommand = new MethodUpdateCommand(this);
}
public void SaveChanges()
{
ChildViewModel = new PropertyViewModel(_method.Name,
_method.Helper);
}
}
ChildView
class PropertyViewModel : INotifyPropertyChanged
{
private ObservableCollection<Property> _properties;
public ObservableCollection<Property> Properties
{
get { return _properties; }
//set { _properties = value; }
}
public PropertyViewModel(string method, string reflection)
{
_properties = new ObservableCollection<Property>();
CollectProperties(method, reflection);
}
Property control .xaml
<StackPanel x:Name="Test" Grid.Row="1">
<ItemsControl ItemsSource = "{Binding ChildViewModel.Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<Label Content="{Binding Name}"></Label>
<TextBox Text = "{Binding Path, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding StdDev, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Unit, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
My child view is updated in the debugger, but the view is not updated, I am not sure what am I missing
wpf dynamic data-binding user-controls
add a comment |
up vote
0
down vote
favorite
I am new to WPF and C#,
I have a main screen consist of multiple user controls and some of the need to be destroyed and recreate on the fly based on the selection of one.
Here is my sample WMMW code,
Models
public class Method : INotifyPropertyChanged, IDataErrorInfo
{
#region properties
private string _method;
private string _helper;
#endregion
public Method()
{
_method = "MM1";
_helper = "HM1";
}
//getter setters..
}
public class Property : INotifyPropertyChanged
{
#region Properties
private string _name;
private string _path;
private float _standarddeviation;
private string _unit;
//getter setters
}
MethodViewModel
class MethodViewModel
{
#region Properties
private Method _method;
#endregion
#region Getter & Setters
public Method Method
{
get { return _method; }
}
public ICommand UpdateCommand
{
get; private set;
}
#endregion
#region Constructor
/// <summary>
/// Initialize a new interface of the MEthodViewModel class
/// </summary>
public MethodViewModel()
{
//test
_method = new Method();
UpdateCommand = new MethodUpdateCommand(this);
}
#endregion
#region Functions
public void SaveChanges()
{
//TODO: Destroy and rebuild the usercontrol
}
#endregion
}
Command
class MethodUpdateCommand : ICommand
{
private MethodViewModel _viewModel;
/// <summary>
/// Initialize a new instance of MethodNameUpdate Command
/// </summary>
/// <param name="viewModel"></param>
public MethodUpdateCommand(MethodViewModel viewModel)
{
_viewModel = viewModel;
}
#region ICOmmand Members
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return String.IsNullOrWhiteSpace(_viewModel.Method.Error);
}
public void Execute(object parameter)
{
_viewModel.SaveChanges();
}
#endregion
}
Main screen
<Window x:Class="WpfApplicationTest.Views.MainScreen"
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:WpfApplicationTest.Views"
xmlns:control="clr-namespace:WpfApplicationTest.Controls"
mc:Ignorable="d"
Title="MainScreen" Height="573.763" Width="354.839">
<Grid Margin="0,0,0,-41">
<control:MethodControl Margin="21,23,63,460" RenderTransformOrigin="0.507,0.567"></control:MethodControl>
<control:PropertyControl Margin="0,129,0,-129"></control:PropertyControl>
</Grid>
Method Control
<UserControl x:Class="WpfApplicationTest.Controls.MethodControl"
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"
xmlns:local="clr-namespace:WpfApplicationTest.Controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d" d:DesignWidth="300" Height="101.075">
<WrapPanel Orientation=" Horizontal" VerticalAlignment="Top" Height="120" >
<Label Content="Method Name:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource MethodNames}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Label Content="Reflection Type:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Helper, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource HelperMethods}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</WrapPanel>
Property control.xaml
<StackPanel Name="Test"></StackPanel>
public partial class PropertyControl : UserControl
{
public PropertyControl()
{
InitializeComponent();
PopulatePropertyPanel("MM1", "HM1");
}
private void PopulatePropertyPanel(string name, string reflection)
{
//TODO: decide which mthod
//int methodindex = Constant.GetMethodNameIndex(name);
int methodindex = Array.IndexOf((String)Application.Current.Resources["MethodNames"], name);
switch (methodindex)
{
case 0:
foreach (String prop in (String)Application.Current.Resources["Result1"])
{
PopulateProperty(prop, true);
}
break;
default:
foreach (String prop in (String)Application.Current.Resources["Result2"])
{
PopulateProperty(prop, false);
}
break;
}
}
private void PopulateProperty(string prop, Boolean constant)
{
Label lbl = new Label();
lbl.Content = prop;
TextBox pathtext = new TextBox();
pathtext.Text = "path";
TextBox std = new TextBox();
std.Text = "std";
TextBox unit = new TextBox();
unit.Text = "unit";
Test.Children.Add(lbl);
Test.Children.Add(pathtext);
Test.Children.Add(std);
Test.Children.Add(unit);
}
}
I want to recreate populate property-control, every time there is a change in method-control, which I already create a command for it.
Also, how can I bind the components in property control with property model,
I need to have a collection of properties (1 property for each result, and destroy and rebuild the collection with property-control.
EDIT 1:
Main window
<ContentControl Grid.Row="1" Content="{Binding ChildViewModel}" />
Resources
<DataTemplate DataType="{x:Type modelViews:PropertyViewModel}">
<control:PropertyControl />
</DataTemplate>
MainViewModel
class MethodViewModel : INotifyPropertyChanged
{
#region Properties
private Method _method;
private PropertyViewModel _childViewModel;
#endregion
#region Getter & Setters
public PropertyViewModel ChildViewModel
{
get { return this._childViewModel; }
set
{
if (this._childViewModel != value)
{
this._childViewModel = value;
OnPropertyChanged("ChildViewModel");
}
}
}
public MethodViewModel()
{
//test
_method = new Method();
_childViewModel = new PropertyViewModel();
_childViewModel.CollectProperties(_method.Name, _method.Helper);
UpdateCommand = new MethodUpdateCommand(this);
}
public void SaveChanges()
{
ChildViewModel = new PropertyViewModel(_method.Name,
_method.Helper);
}
}
ChildView
class PropertyViewModel : INotifyPropertyChanged
{
private ObservableCollection<Property> _properties;
public ObservableCollection<Property> Properties
{
get { return _properties; }
//set { _properties = value; }
}
public PropertyViewModel(string method, string reflection)
{
_properties = new ObservableCollection<Property>();
CollectProperties(method, reflection);
}
Property control .xaml
<StackPanel x:Name="Test" Grid.Row="1">
<ItemsControl ItemsSource = "{Binding ChildViewModel.Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<Label Content="{Binding Name}"></Label>
<TextBox Text = "{Binding Path, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding StdDev, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Unit, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
My child view is updated in the debugger, but the view is not updated, I am not sure what am I missing
wpf dynamic data-binding user-controls
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I am new to WPF and C#,
I have a main screen consist of multiple user controls and some of the need to be destroyed and recreate on the fly based on the selection of one.
Here is my sample WMMW code,
Models
public class Method : INotifyPropertyChanged, IDataErrorInfo
{
#region properties
private string _method;
private string _helper;
#endregion
public Method()
{
_method = "MM1";
_helper = "HM1";
}
//getter setters..
}
public class Property : INotifyPropertyChanged
{
#region Properties
private string _name;
private string _path;
private float _standarddeviation;
private string _unit;
//getter setters
}
MethodViewModel
class MethodViewModel
{
#region Properties
private Method _method;
#endregion
#region Getter & Setters
public Method Method
{
get { return _method; }
}
public ICommand UpdateCommand
{
get; private set;
}
#endregion
#region Constructor
/// <summary>
/// Initialize a new interface of the MEthodViewModel class
/// </summary>
public MethodViewModel()
{
//test
_method = new Method();
UpdateCommand = new MethodUpdateCommand(this);
}
#endregion
#region Functions
public void SaveChanges()
{
//TODO: Destroy and rebuild the usercontrol
}
#endregion
}
Command
class MethodUpdateCommand : ICommand
{
private MethodViewModel _viewModel;
/// <summary>
/// Initialize a new instance of MethodNameUpdate Command
/// </summary>
/// <param name="viewModel"></param>
public MethodUpdateCommand(MethodViewModel viewModel)
{
_viewModel = viewModel;
}
#region ICOmmand Members
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return String.IsNullOrWhiteSpace(_viewModel.Method.Error);
}
public void Execute(object parameter)
{
_viewModel.SaveChanges();
}
#endregion
}
Main screen
<Window x:Class="WpfApplicationTest.Views.MainScreen"
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:WpfApplicationTest.Views"
xmlns:control="clr-namespace:WpfApplicationTest.Controls"
mc:Ignorable="d"
Title="MainScreen" Height="573.763" Width="354.839">
<Grid Margin="0,0,0,-41">
<control:MethodControl Margin="21,23,63,460" RenderTransformOrigin="0.507,0.567"></control:MethodControl>
<control:PropertyControl Margin="0,129,0,-129"></control:PropertyControl>
</Grid>
Method Control
<UserControl x:Class="WpfApplicationTest.Controls.MethodControl"
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"
xmlns:local="clr-namespace:WpfApplicationTest.Controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d" d:DesignWidth="300" Height="101.075">
<WrapPanel Orientation=" Horizontal" VerticalAlignment="Top" Height="120" >
<Label Content="Method Name:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource MethodNames}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Label Content="Reflection Type:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Helper, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource HelperMethods}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</WrapPanel>
Property control.xaml
<StackPanel Name="Test"></StackPanel>
public partial class PropertyControl : UserControl
{
public PropertyControl()
{
InitializeComponent();
PopulatePropertyPanel("MM1", "HM1");
}
private void PopulatePropertyPanel(string name, string reflection)
{
//TODO: decide which mthod
//int methodindex = Constant.GetMethodNameIndex(name);
int methodindex = Array.IndexOf((String)Application.Current.Resources["MethodNames"], name);
switch (methodindex)
{
case 0:
foreach (String prop in (String)Application.Current.Resources["Result1"])
{
PopulateProperty(prop, true);
}
break;
default:
foreach (String prop in (String)Application.Current.Resources["Result2"])
{
PopulateProperty(prop, false);
}
break;
}
}
private void PopulateProperty(string prop, Boolean constant)
{
Label lbl = new Label();
lbl.Content = prop;
TextBox pathtext = new TextBox();
pathtext.Text = "path";
TextBox std = new TextBox();
std.Text = "std";
TextBox unit = new TextBox();
unit.Text = "unit";
Test.Children.Add(lbl);
Test.Children.Add(pathtext);
Test.Children.Add(std);
Test.Children.Add(unit);
}
}
I want to recreate populate property-control, every time there is a change in method-control, which I already create a command for it.
Also, how can I bind the components in property control with property model,
I need to have a collection of properties (1 property for each result, and destroy and rebuild the collection with property-control.
EDIT 1:
Main window
<ContentControl Grid.Row="1" Content="{Binding ChildViewModel}" />
Resources
<DataTemplate DataType="{x:Type modelViews:PropertyViewModel}">
<control:PropertyControl />
</DataTemplate>
MainViewModel
class MethodViewModel : INotifyPropertyChanged
{
#region Properties
private Method _method;
private PropertyViewModel _childViewModel;
#endregion
#region Getter & Setters
public PropertyViewModel ChildViewModel
{
get { return this._childViewModel; }
set
{
if (this._childViewModel != value)
{
this._childViewModel = value;
OnPropertyChanged("ChildViewModel");
}
}
}
public MethodViewModel()
{
//test
_method = new Method();
_childViewModel = new PropertyViewModel();
_childViewModel.CollectProperties(_method.Name, _method.Helper);
UpdateCommand = new MethodUpdateCommand(this);
}
public void SaveChanges()
{
ChildViewModel = new PropertyViewModel(_method.Name,
_method.Helper);
}
}
ChildView
class PropertyViewModel : INotifyPropertyChanged
{
private ObservableCollection<Property> _properties;
public ObservableCollection<Property> Properties
{
get { return _properties; }
//set { _properties = value; }
}
public PropertyViewModel(string method, string reflection)
{
_properties = new ObservableCollection<Property>();
CollectProperties(method, reflection);
}
Property control .xaml
<StackPanel x:Name="Test" Grid.Row="1">
<ItemsControl ItemsSource = "{Binding ChildViewModel.Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<Label Content="{Binding Name}"></Label>
<TextBox Text = "{Binding Path, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding StdDev, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Unit, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
My child view is updated in the debugger, but the view is not updated, I am not sure what am I missing
wpf dynamic data-binding user-controls
I am new to WPF and C#,
I have a main screen consist of multiple user controls and some of the need to be destroyed and recreate on the fly based on the selection of one.
Here is my sample WMMW code,
Models
public class Method : INotifyPropertyChanged, IDataErrorInfo
{
#region properties
private string _method;
private string _helper;
#endregion
public Method()
{
_method = "MM1";
_helper = "HM1";
}
//getter setters..
}
public class Property : INotifyPropertyChanged
{
#region Properties
private string _name;
private string _path;
private float _standarddeviation;
private string _unit;
//getter setters
}
MethodViewModel
class MethodViewModel
{
#region Properties
private Method _method;
#endregion
#region Getter & Setters
public Method Method
{
get { return _method; }
}
public ICommand UpdateCommand
{
get; private set;
}
#endregion
#region Constructor
/// <summary>
/// Initialize a new interface of the MEthodViewModel class
/// </summary>
public MethodViewModel()
{
//test
_method = new Method();
UpdateCommand = new MethodUpdateCommand(this);
}
#endregion
#region Functions
public void SaveChanges()
{
//TODO: Destroy and rebuild the usercontrol
}
#endregion
}
Command
class MethodUpdateCommand : ICommand
{
private MethodViewModel _viewModel;
/// <summary>
/// Initialize a new instance of MethodNameUpdate Command
/// </summary>
/// <param name="viewModel"></param>
public MethodUpdateCommand(MethodViewModel viewModel)
{
_viewModel = viewModel;
}
#region ICOmmand Members
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return String.IsNullOrWhiteSpace(_viewModel.Method.Error);
}
public void Execute(object parameter)
{
_viewModel.SaveChanges();
}
#endregion
}
Main screen
<Window x:Class="WpfApplicationTest.Views.MainScreen"
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:WpfApplicationTest.Views"
xmlns:control="clr-namespace:WpfApplicationTest.Controls"
mc:Ignorable="d"
Title="MainScreen" Height="573.763" Width="354.839">
<Grid Margin="0,0,0,-41">
<control:MethodControl Margin="21,23,63,460" RenderTransformOrigin="0.507,0.567"></control:MethodControl>
<control:PropertyControl Margin="0,129,0,-129"></control:PropertyControl>
</Grid>
Method Control
<UserControl x:Class="WpfApplicationTest.Controls.MethodControl"
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"
xmlns:local="clr-namespace:WpfApplicationTest.Controls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d" d:DesignWidth="300" Height="101.075">
<WrapPanel Orientation=" Horizontal" VerticalAlignment="Top" Height="120" >
<Label Content="Method Name:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource MethodNames}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Label Content="Reflection Type:" Width="113"/>
<ComboBox Width="160" SelectedItem="{Binding Method.Helper, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" ItemsSource="{StaticResource HelperMethods}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</WrapPanel>
Property control.xaml
<StackPanel Name="Test"></StackPanel>
public partial class PropertyControl : UserControl
{
public PropertyControl()
{
InitializeComponent();
PopulatePropertyPanel("MM1", "HM1");
}
private void PopulatePropertyPanel(string name, string reflection)
{
//TODO: decide which mthod
//int methodindex = Constant.GetMethodNameIndex(name);
int methodindex = Array.IndexOf((String)Application.Current.Resources["MethodNames"], name);
switch (methodindex)
{
case 0:
foreach (String prop in (String)Application.Current.Resources["Result1"])
{
PopulateProperty(prop, true);
}
break;
default:
foreach (String prop in (String)Application.Current.Resources["Result2"])
{
PopulateProperty(prop, false);
}
break;
}
}
private void PopulateProperty(string prop, Boolean constant)
{
Label lbl = new Label();
lbl.Content = prop;
TextBox pathtext = new TextBox();
pathtext.Text = "path";
TextBox std = new TextBox();
std.Text = "std";
TextBox unit = new TextBox();
unit.Text = "unit";
Test.Children.Add(lbl);
Test.Children.Add(pathtext);
Test.Children.Add(std);
Test.Children.Add(unit);
}
}
I want to recreate populate property-control, every time there is a change in method-control, which I already create a command for it.
Also, how can I bind the components in property control with property model,
I need to have a collection of properties (1 property for each result, and destroy and rebuild the collection with property-control.
EDIT 1:
Main window
<ContentControl Grid.Row="1" Content="{Binding ChildViewModel}" />
Resources
<DataTemplate DataType="{x:Type modelViews:PropertyViewModel}">
<control:PropertyControl />
</DataTemplate>
MainViewModel
class MethodViewModel : INotifyPropertyChanged
{
#region Properties
private Method _method;
private PropertyViewModel _childViewModel;
#endregion
#region Getter & Setters
public PropertyViewModel ChildViewModel
{
get { return this._childViewModel; }
set
{
if (this._childViewModel != value)
{
this._childViewModel = value;
OnPropertyChanged("ChildViewModel");
}
}
}
public MethodViewModel()
{
//test
_method = new Method();
_childViewModel = new PropertyViewModel();
_childViewModel.CollectProperties(_method.Name, _method.Helper);
UpdateCommand = new MethodUpdateCommand(this);
}
public void SaveChanges()
{
ChildViewModel = new PropertyViewModel(_method.Name,
_method.Helper);
}
}
ChildView
class PropertyViewModel : INotifyPropertyChanged
{
private ObservableCollection<Property> _properties;
public ObservableCollection<Property> Properties
{
get { return _properties; }
//set { _properties = value; }
}
public PropertyViewModel(string method, string reflection)
{
_properties = new ObservableCollection<Property>();
CollectProperties(method, reflection);
}
Property control .xaml
<StackPanel x:Name="Test" Grid.Row="1">
<ItemsControl ItemsSource = "{Binding ChildViewModel.Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<Label Content="{Binding Name}"></Label>
<TextBox Text = "{Binding Path, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding StdDev, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Unit, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
My child view is updated in the debugger, but the view is not updated, I am not sure what am I missing
wpf dynamic data-binding user-controls
wpf dynamic data-binding user-controls
edited yesterday
asked 2 days ago
Guray Golcuk
174
174
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
In general you solve this with ContentControls and DataTemplates. Let's say you have a MainViewModel and you want to be able to display a child view model, so you start by exposing a property with property change notification, i.e. something like this:
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
Over in the XAML for your main window you create a content control and bind it to this property:
<ContentControl Content="{Binding MyChild}" />
Finally in your resources block you create a DataTemplate for each child view model that you might assign to this property:
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<local:ChildViewControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ChildViewModel2}">
<local:ChildViewControl2 />
</DataTemplate>
... etc...
Ordinarily this control won't be visible, but as soon as you assign an appropriate view model to the property it will automatically populate based on what you've specified in your data templates:
this.MyChild = new ChildViewModel(); // <-- child control gets created and appears
In practice your property wouldn't be of type object
, you usually have some base class that all your child view models are derived from, but you get the idea.
There are other ways to do this (e.g. DataTriggers) but DataTemplates are what you usually use for cases such as what you've described.
UPDATE: Here's some fully working code, imagine your MainViewModel has a property for a child view model and a couple of button handlers to set and clear the child:
public class MainViewModel : ViewModelBase
{
// Child property
private ChildViewModel _Child;
public ChildViewModel Child
{
get { return this._Child; }
set
{
if (this._Child != value)
{
this._Child = value;
RaisePropertyChanged(() => this.Child);
}
}
}
// Set child
private ICommand _SetChildCommand;
public ICommand SetChildCommand => this._SetChildCommand ?? (this._SetChildCommand = new RelayCommand(OnSetChild));
private void OnSetChild()
{
this.Child = new ChildViewModel();
}
// Clear child
private ICommand _ClearChildCommand;
public ICommand ClearChildCommand => this._ClearChildCommand ?? (this._ClearChildCommand = new RelayCommand(OnClearChild));
private void OnClearChild()
{
this.Child = null;
}
}
public class ChildViewModel : ViewModelBase
{
public string Text => "I am child type 1!";
}
Then in your XAML all you need to do is this:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<Button Content="Set Child" Command="{Binding SetChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<Button Content="Clear Child" Command="{Binding ClearChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<ContentControl Content="{Binding Child}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<TextBlock Text="{Binding Text}" Foreground="Yellow" Background="Blue" HorizontalAlignment="Left" VerticalAlignment="Center" />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</StackPanel>
Initially you'll only see the two buttons by themselves, but clicking on "Set Child" will cause the OnSetChild
handler to get called, which will create a new instance of ChildViewModel and assign it to the property. Because of the DataTemplate the ContentControl will be automatically populated:
Likewise, clicking the "Clear child" button will clear the property and the yellow/blue text will disappear. (I'm using a TextBlock here but obviously you can use anything you want, including your own custom controls).
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
1
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
1
So when you put a breakpoint inOnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?
– Mark Feldman
yesterday
1
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
1
In your property control you should be binding toProperties
, notChildViewModel.Properties
. When you do a<ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.
– Mark Feldman
yesterday
|
show 3 more comments
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
In general you solve this with ContentControls and DataTemplates. Let's say you have a MainViewModel and you want to be able to display a child view model, so you start by exposing a property with property change notification, i.e. something like this:
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
Over in the XAML for your main window you create a content control and bind it to this property:
<ContentControl Content="{Binding MyChild}" />
Finally in your resources block you create a DataTemplate for each child view model that you might assign to this property:
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<local:ChildViewControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ChildViewModel2}">
<local:ChildViewControl2 />
</DataTemplate>
... etc...
Ordinarily this control won't be visible, but as soon as you assign an appropriate view model to the property it will automatically populate based on what you've specified in your data templates:
this.MyChild = new ChildViewModel(); // <-- child control gets created and appears
In practice your property wouldn't be of type object
, you usually have some base class that all your child view models are derived from, but you get the idea.
There are other ways to do this (e.g. DataTriggers) but DataTemplates are what you usually use for cases such as what you've described.
UPDATE: Here's some fully working code, imagine your MainViewModel has a property for a child view model and a couple of button handlers to set and clear the child:
public class MainViewModel : ViewModelBase
{
// Child property
private ChildViewModel _Child;
public ChildViewModel Child
{
get { return this._Child; }
set
{
if (this._Child != value)
{
this._Child = value;
RaisePropertyChanged(() => this.Child);
}
}
}
// Set child
private ICommand _SetChildCommand;
public ICommand SetChildCommand => this._SetChildCommand ?? (this._SetChildCommand = new RelayCommand(OnSetChild));
private void OnSetChild()
{
this.Child = new ChildViewModel();
}
// Clear child
private ICommand _ClearChildCommand;
public ICommand ClearChildCommand => this._ClearChildCommand ?? (this._ClearChildCommand = new RelayCommand(OnClearChild));
private void OnClearChild()
{
this.Child = null;
}
}
public class ChildViewModel : ViewModelBase
{
public string Text => "I am child type 1!";
}
Then in your XAML all you need to do is this:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<Button Content="Set Child" Command="{Binding SetChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<Button Content="Clear Child" Command="{Binding ClearChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<ContentControl Content="{Binding Child}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<TextBlock Text="{Binding Text}" Foreground="Yellow" Background="Blue" HorizontalAlignment="Left" VerticalAlignment="Center" />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</StackPanel>
Initially you'll only see the two buttons by themselves, but clicking on "Set Child" will cause the OnSetChild
handler to get called, which will create a new instance of ChildViewModel and assign it to the property. Because of the DataTemplate the ContentControl will be automatically populated:
Likewise, clicking the "Clear child" button will clear the property and the yellow/blue text will disappear. (I'm using a TextBlock here but obviously you can use anything you want, including your own custom controls).
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
1
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
1
So when you put a breakpoint inOnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?
– Mark Feldman
yesterday
1
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
1
In your property control you should be binding toProperties
, notChildViewModel.Properties
. When you do a<ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.
– Mark Feldman
yesterday
|
show 3 more comments
up vote
1
down vote
accepted
In general you solve this with ContentControls and DataTemplates. Let's say you have a MainViewModel and you want to be able to display a child view model, so you start by exposing a property with property change notification, i.e. something like this:
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
Over in the XAML for your main window you create a content control and bind it to this property:
<ContentControl Content="{Binding MyChild}" />
Finally in your resources block you create a DataTemplate for each child view model that you might assign to this property:
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<local:ChildViewControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ChildViewModel2}">
<local:ChildViewControl2 />
</DataTemplate>
... etc...
Ordinarily this control won't be visible, but as soon as you assign an appropriate view model to the property it will automatically populate based on what you've specified in your data templates:
this.MyChild = new ChildViewModel(); // <-- child control gets created and appears
In practice your property wouldn't be of type object
, you usually have some base class that all your child view models are derived from, but you get the idea.
There are other ways to do this (e.g. DataTriggers) but DataTemplates are what you usually use for cases such as what you've described.
UPDATE: Here's some fully working code, imagine your MainViewModel has a property for a child view model and a couple of button handlers to set and clear the child:
public class MainViewModel : ViewModelBase
{
// Child property
private ChildViewModel _Child;
public ChildViewModel Child
{
get { return this._Child; }
set
{
if (this._Child != value)
{
this._Child = value;
RaisePropertyChanged(() => this.Child);
}
}
}
// Set child
private ICommand _SetChildCommand;
public ICommand SetChildCommand => this._SetChildCommand ?? (this._SetChildCommand = new RelayCommand(OnSetChild));
private void OnSetChild()
{
this.Child = new ChildViewModel();
}
// Clear child
private ICommand _ClearChildCommand;
public ICommand ClearChildCommand => this._ClearChildCommand ?? (this._ClearChildCommand = new RelayCommand(OnClearChild));
private void OnClearChild()
{
this.Child = null;
}
}
public class ChildViewModel : ViewModelBase
{
public string Text => "I am child type 1!";
}
Then in your XAML all you need to do is this:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<Button Content="Set Child" Command="{Binding SetChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<Button Content="Clear Child" Command="{Binding ClearChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<ContentControl Content="{Binding Child}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<TextBlock Text="{Binding Text}" Foreground="Yellow" Background="Blue" HorizontalAlignment="Left" VerticalAlignment="Center" />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</StackPanel>
Initially you'll only see the two buttons by themselves, but clicking on "Set Child" will cause the OnSetChild
handler to get called, which will create a new instance of ChildViewModel and assign it to the property. Because of the DataTemplate the ContentControl will be automatically populated:
Likewise, clicking the "Clear child" button will clear the property and the yellow/blue text will disappear. (I'm using a TextBlock here but obviously you can use anything you want, including your own custom controls).
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
1
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
1
So when you put a breakpoint inOnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?
– Mark Feldman
yesterday
1
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
1
In your property control you should be binding toProperties
, notChildViewModel.Properties
. When you do a<ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.
– Mark Feldman
yesterday
|
show 3 more comments
up vote
1
down vote
accepted
up vote
1
down vote
accepted
In general you solve this with ContentControls and DataTemplates. Let's say you have a MainViewModel and you want to be able to display a child view model, so you start by exposing a property with property change notification, i.e. something like this:
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
Over in the XAML for your main window you create a content control and bind it to this property:
<ContentControl Content="{Binding MyChild}" />
Finally in your resources block you create a DataTemplate for each child view model that you might assign to this property:
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<local:ChildViewControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ChildViewModel2}">
<local:ChildViewControl2 />
</DataTemplate>
... etc...
Ordinarily this control won't be visible, but as soon as you assign an appropriate view model to the property it will automatically populate based on what you've specified in your data templates:
this.MyChild = new ChildViewModel(); // <-- child control gets created and appears
In practice your property wouldn't be of type object
, you usually have some base class that all your child view models are derived from, but you get the idea.
There are other ways to do this (e.g. DataTriggers) but DataTemplates are what you usually use for cases such as what you've described.
UPDATE: Here's some fully working code, imagine your MainViewModel has a property for a child view model and a couple of button handlers to set and clear the child:
public class MainViewModel : ViewModelBase
{
// Child property
private ChildViewModel _Child;
public ChildViewModel Child
{
get { return this._Child; }
set
{
if (this._Child != value)
{
this._Child = value;
RaisePropertyChanged(() => this.Child);
}
}
}
// Set child
private ICommand _SetChildCommand;
public ICommand SetChildCommand => this._SetChildCommand ?? (this._SetChildCommand = new RelayCommand(OnSetChild));
private void OnSetChild()
{
this.Child = new ChildViewModel();
}
// Clear child
private ICommand _ClearChildCommand;
public ICommand ClearChildCommand => this._ClearChildCommand ?? (this._ClearChildCommand = new RelayCommand(OnClearChild));
private void OnClearChild()
{
this.Child = null;
}
}
public class ChildViewModel : ViewModelBase
{
public string Text => "I am child type 1!";
}
Then in your XAML all you need to do is this:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<Button Content="Set Child" Command="{Binding SetChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<Button Content="Clear Child" Command="{Binding ClearChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<ContentControl Content="{Binding Child}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<TextBlock Text="{Binding Text}" Foreground="Yellow" Background="Blue" HorizontalAlignment="Left" VerticalAlignment="Center" />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</StackPanel>
Initially you'll only see the two buttons by themselves, but clicking on "Set Child" will cause the OnSetChild
handler to get called, which will create a new instance of ChildViewModel and assign it to the property. Because of the DataTemplate the ContentControl will be automatically populated:
Likewise, clicking the "Clear child" button will clear the property and the yellow/blue text will disappear. (I'm using a TextBlock here but obviously you can use anything you want, including your own custom controls).
In general you solve this with ContentControls and DataTemplates. Let's say you have a MainViewModel and you want to be able to display a child view model, so you start by exposing a property with property change notification, i.e. something like this:
private object _MyChild;
public object MyChild
{
get { return this._MyChild; }
set
{
if (this._MyChild != value)
{
this._MyChild = value;
RaisePropertyChanged(() => this.MyChild);
}
}
}
Over in the XAML for your main window you create a content control and bind it to this property:
<ContentControl Content="{Binding MyChild}" />
Finally in your resources block you create a DataTemplate for each child view model that you might assign to this property:
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<local:ChildViewControl />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ChildViewModel2}">
<local:ChildViewControl2 />
</DataTemplate>
... etc...
Ordinarily this control won't be visible, but as soon as you assign an appropriate view model to the property it will automatically populate based on what you've specified in your data templates:
this.MyChild = new ChildViewModel(); // <-- child control gets created and appears
In practice your property wouldn't be of type object
, you usually have some base class that all your child view models are derived from, but you get the idea.
There are other ways to do this (e.g. DataTriggers) but DataTemplates are what you usually use for cases such as what you've described.
UPDATE: Here's some fully working code, imagine your MainViewModel has a property for a child view model and a couple of button handlers to set and clear the child:
public class MainViewModel : ViewModelBase
{
// Child property
private ChildViewModel _Child;
public ChildViewModel Child
{
get { return this._Child; }
set
{
if (this._Child != value)
{
this._Child = value;
RaisePropertyChanged(() => this.Child);
}
}
}
// Set child
private ICommand _SetChildCommand;
public ICommand SetChildCommand => this._SetChildCommand ?? (this._SetChildCommand = new RelayCommand(OnSetChild));
private void OnSetChild()
{
this.Child = new ChildViewModel();
}
// Clear child
private ICommand _ClearChildCommand;
public ICommand ClearChildCommand => this._ClearChildCommand ?? (this._ClearChildCommand = new RelayCommand(OnClearChild));
private void OnClearChild()
{
this.Child = null;
}
}
public class ChildViewModel : ViewModelBase
{
public string Text => "I am child type 1!";
}
Then in your XAML all you need to do is this:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<Button Content="Set Child" Command="{Binding SetChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<Button Content="Clear Child" Command="{Binding ClearChildCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5" />
<ContentControl Content="{Binding Child}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<TextBlock Text="{Binding Text}" Foreground="Yellow" Background="Blue" HorizontalAlignment="Left" VerticalAlignment="Center" />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</StackPanel>
Initially you'll only see the two buttons by themselves, but clicking on "Set Child" will cause the OnSetChild
handler to get called, which will create a new instance of ChildViewModel and assign it to the property. Because of the DataTemplate the ContentControl will be automatically populated:
Likewise, clicking the "Clear child" button will clear the property and the yellow/blue text will disappear. (I'm using a TextBlock here but obviously you can use anything you want, including your own custom controls).
edited yesterday
answered 2 days ago
Mark Feldman
7,86911638
7,86911638
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
1
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
1
So when you put a breakpoint inOnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?
– Mark Feldman
yesterday
1
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
1
In your property control you should be binding toProperties
, notChildViewModel.Properties
. When you do a<ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.
– Mark Feldman
yesterday
|
show 3 more comments
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
1
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
1
So when you put a breakpoint inOnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?
– Mark Feldman
yesterday
1
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
1
In your property control you should be binding toProperties
, notChildViewModel.Properties
. When you do a<ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.
– Mark Feldman
yesterday
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
Thank you, it helps me to solve some of my problems but I still couldn't manage with dynamic user-control change ` public object _model; public object _ childView ` I couldn't figure it out how the change in the model, updates the current model-control (destroy and recreate)
– Guray Golcuk
2 days ago
1
1
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
I don't really know how to describe it more clearly than that....if you bind a ContentControl to your data, and use a DataTemplate for your view model data type, the content of the DataTemplate will appear as a child of the ContentControl. Set the property to null and it'll be destroyed. If you still can't get it to work then post some code that uses ContentControl and DataTemplate and I'll tell you what you're doing wrong.
– Mark Feldman
yesterday
1
1
So when you put a breakpoint in
OnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?– Mark Feldman
yesterday
So when you put a breakpoint in
OnSetChild
it gets hit when you press the button? Have you made any other changes to the code at all?– Mark Feldman
yesterday
1
1
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
In particular, is your property change notification the same i.e. MVVM Lite? Because if your call to RaisePropertyChanged is broken, or the parent class (MainViewModel) doesn't support property change notification, then it won't work.
– Mark Feldman
yesterday
1
1
In your property control you should be binding to
Properties
, not ChildViewModel.Properties
. When you do a <ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.– Mark Feldman
yesterday
In your property control you should be binding to
Properties
, not ChildViewModel.Properties
. When you do a <ContentControl Content="{Binding ChildViewModel}" />
back in your main window xaml it already sets the DataContext for whatever is inside the ContentControl to the binding, i.e. ChildViewModel.– Mark Feldman
yesterday
|
show 3 more comments
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53187784%2fwpf-how-to-destroy-and-recreate-usercontrol-based-on-changes-in-other-bindin%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password