I need show two line series on single area. They are have share X-axis (DateTime) and different Y-axis.
Use CategoryXAxis
If I used CategoryXAxis type for X-axis than I see two series, but they are not synchronized by X-axis (you can see it on tooltip).
_categoryXAxis = new CategoryXAxis()
{
ItemsSource = enumerable,
FontSize = 10,
};
Use CategoryDateTimeXAxis
If I using CategoryDateTimeXAxis type for X-axis than I see SINGLE series, and I see two tooltip, but they are not synchronized by X-axis (you can see it on tooltip).
_categoryXAxis = new CategoryDateTimeXAxis()
{
ItemsSource = enumerable,
DateTimeMemberPath = "DateTime",
DisplayType = TimeAxisDisplayType.Continuous,
FontSize = 10,
MinimumValue = new DateTime(2000, 1, 1),
MaximumValue = new DateTime(2017, 1, 1),
};
What can I do?
The example below demonstrates how to synchronize the DateTime axis for two series:
MainWindow.xaml
<Window x:Class="xamDataChartMultipleSeries.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ig="http://schemas.infragistics.com/xaml"
Title="XamDataChart" Height="350" Width="525" >
<Grid>
<Grid.Resources>
<DataTemplate x:Key="DataTrackerTemplate">
<Ellipse Stretch="Fill" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
MinWidth="15" MinHeight="15" StrokeThickness="0.5"
Fill="{Binding Path=ActualItemBrush}" Stroke="{Binding Path=Series.ActualMarkerOutline}" >
</Ellipse>
</DataTemplate>
</Grid.Resources>
<ig:XamDataChart Name="MultipleSeriesChart" Padding="5"
OverviewPlusDetailPaneVisibility="Collapsed"
OverviewPlusDetailPaneHorizontalAlignment="Left"
OverviewPlusDetailPaneVerticalAlignment="Bottom" >
<ig:XamDataChart.Axes>
<ig:CategoryDateTimeXAxis x:Name="xAxis" Title="TIME (min)" Label="{}{DateTime:MM/dd/yyyy}" DateTimeMemberPath="DateTime" DisplayType="Discrete" >
<ig:CategoryDateTimeXAxis.LabelSettings>
<ig:AxisLabelSettings Location="OutsideBottom" Angle="40" />
</ig:CategoryDateTimeXAxis.LabelSettings>
</ig:CategoryDateTimeXAxis>
<ig:NumericYAxis x:Name="yAxis" Title="" Label="{}{0:0.##}" Interval="0.25" />
</ig:XamDataChart.Axes>
<ig:XamDataChart.Series>
<ig:LineSeries x:Name="Series1" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Series1"
MarkerType="None" Thickness="2" IsTransitionInEnabled="True" IsHighlightingEnabled="True" Brush="Blue" >
<ig:LineSeries.ToolTip>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="X= " />
<TextBlock Text="{Binding Item.DateTime}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
<TextBlock Text="Y= " />
<TextBlock Text="{Binding Item.Series1, StringFormat={}{0:#,0.000}}" />
</StackPanel>
</StackPanel>
</ig:LineSeries.ToolTip>
</ig:LineSeries>
<ig:LineSeries x:Name="Series2" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Series2"
MarkerType="None" Thickness="2" IsTransitionInEnabled="True" IsHighlightingEnabled="True" Brush="Green">
<ig:LineSeries.ToolTip>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="X= " />
<TextBlock Text="{Binding Item.DateTime}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
<TextBlock Text="Y= " />
<TextBlock Text="{Binding Item.Series2, StringFormat={}{0:#,0.000}}" />
</StackPanel>
</StackPanel>
</ig:LineSeries.ToolTip>
</ig:LineSeries>
<ig:CategoryItemHighlightLayer x:Name="TackingLayer" Opacity="1" MarkerTemplate="{StaticResource DataTrackerTemplate}" UseInterpolation="True"
TransitionDuration="0:00:00.1" Canvas.ZIndex="11" />
<ig:ItemToolTipLayer x:Name="ToolTipLayer" Canvas.ZIndex="12" UseInterpolation="True" TransitionDuration="0:00:00.1" />
<ig:CrosshairLayer x:Name="CrosshairLayer" Opacity="1" Thickness="1" Canvas.ZIndex="15" UseInterpolation="True" TransitionDuration="0:00:00.1"/>
</ig:XamDataChart.Series>
</ig:XamDataChart>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;
namespace xamDataChartMultipleSeries
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
int points = 20;
List<Point> data = new List<Point>();
public MainWindow()
{
InitializeComponent();
double x = 0;
var step = 2 * Math.PI / points;
var now = DateTime.Now;
xAxis.MinimumValue = now;
xAxis.MaximumValue = now.AddDays(points);
xAxis.Interval = new TimeSpan(0,6,0,0);
var next = now;
for (var i = 0; i < points; i++, x += step)
{
next = next.AddDays(1);
Data.Add(new ChartDataItem() { DateTime=next, Series1 = Math.Sin(x), Series2 = Math.Cos(x) });
}
if (!DesignerProperties.GetIsInDesignMode(this))
{
xAxis.ItemsSource = Series1.ItemsSource = Series2.ItemsSource = Data;
}
}
// ChartDataCollection
public ChartDataCollection Data = new ChartDataCollection();
}
}
ChartData.cs
using System;
using System.Collections.ObjectModel;
using Infragistics.Samples.Shared.Models;
namespace xamDataChartMultipleSeries
{
public class ChartDataCollection : ObservableCollection<ChartDataItem>
{
public ChartDataCollection() { }
}
public class ChartDataItem : ObservableModel
{
public ChartDataItem() { }
public ChartDataItem(ChartDataItem dataPoint)
{
this.DateTime = dataPoint.DateTime;
this.Series1 = dataPoint.Series1;
this.Series2 = dataPoint.Series2;
}
private DateTime _dt;
public DateTime DateTime
{
get { return _dt; }
set { if (_dt == value) return; _dt = value; }
}
private double _series1;
public double Series1
{
get { return _series1; }
set { if (_series1 == value) return; _series1 = value; OnPropertyChanged("Series1"); }
}
private double _series2;
public double Series2
{
get { return _series2; }
set { if (_series2 == value) return; _series2 = value; OnPropertyChanged("Series2"); }
}
public new string ToString()
{
return base.ToString();
}
}
}
The helper class included to the Infragistics examples:
ObservableModel.cs
using System.ComponentModel;
using System.Runtime.Serialization;
namespace Infragistics.Samples.Shared.Models
{
[DataContract]
public abstract class ObservableModel : INotifyPropertyChanged
{
protected ObservableModel()
{
IsPropertyNotifyActive = true;
}
#region INotifyPropertyChanged
public bool IsPropertyNotifyActive { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected bool HasPropertyChangedHandler()
{
PropertyChangedEventHandler handler = this.PropertyChanged;
return handler != null;
}
protected void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null && IsPropertyNotifyActive)
handler(sender, e);
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
OnPropertyChanged(this, e);
}
protected void OnPropertyChanged(object sender, string propertyName)
{
OnPropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected delegate void PropertyChangedDelegate(object sender, string propertyName);
#endregion
}
}
Related
Problem
I want to refresh my wpf view when a change is made in a List of objects in my application, but it wont register the INotifyChanged method when I change a value.
What I've tried
I went to multiple different stackoverflow pages with sort of the same problem but I don't get it working right. It wont register a change in a object in the list.
my code
below is the code for the MainWindow of the WPF application in wher with the last button click I change the value of XLocation in an object out of a list.
public partial class MainWindow : Window
{
private string filePathArtist { get; set; }
private string filePathGrid { get; set; }
public Game.Game Game { get; set; }
public MainWindow()
{
InitializeComponent();
filePathGrid = String.Empty;
filePathArtist = String.Empty;
}
private void BtnOpen_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
bool? res = openFileDialog.ShowDialog();
if (res == true)
{
string filepathgrid = openFileDialog.FileName;
filePathGrid = filepathgrid;
GridTextBox.Text = filepathgrid;
}
}
private void PickArtistBtn_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
bool? res = openFileDialog.ShowDialog();
if (res == true)
{
string filepathartist = openFileDialog.FileName;
filePathArtist = filepathartist;
ArtistTextBox.Text = filepathartist;
}
}
private void CreateGridBtn_Click(object sender, RoutedEventArgs e)
{
Game = new Game.Game(filePathGrid, filePathArtist);
this.DataContext = Game;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Game.Artists[0].XLocation = 30;
}
}
Next code is the Game class where is implemented a INotfyPropertyChanged on the list of Artists.
public class Game : INotifyPropertyChanged
{
public List<Artist> _artists;
public List<Artist> Artists
{
get
{
return _artists;
}
set
{
_artists = value;
OnPropertyChanged("Artists");
}
}
public List<ITile> Tiles { get; set; }
public Game()
{
}
public Game(string graphPath, string artistPath)
{
IDataParser graphParser = DataFactory.DataFactory.Instance.CreateParser(graphPath);
IDataParser artistParser = DataFactory.DataFactory.Instance.CreateParser(artistPath);
Tiles = graphParser.ParseGridData(graphPath);
Artists = artistParser.ParseArtistData(artistPath);
Test = "new Game";
}
public string Test { get; set; } = "t";
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Ive also added the INotifyPropertyChanged in the Artists class
public class Artist : INotifyPropertyChanged
{
private float _xLocation;
private float _yLocation;
private int _xVelocity;
private int _yVelocity;
public float XLocation
{
get => _xLocation;
set
{
_xLocation = value;
OnPropertyChanged("XLocation");
}
}
public float ConvertedXLoc
{
get => XLocation * (float)3.75;
set { }
}
public float YLocation
{
get => _yLocation;
set
{
_yLocation = value;
OnPropertyChanged("YLocation");
}
}
public float ConvertedYLoc
{
get => YLocation * (float)3.75;
set { }
}
public int XVelocity
{
get => _xVelocity;
set
{
_xVelocity = value;
}
}
public int YVelocity
{
get => _yVelocity;
set
{
_yVelocity = value;
}
}
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then here is the Xaml code where I bind the objects to the wpf UI.
<Window x:Class="BroadwayBoogie.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:game="clr-namespace:BroadwayBoogie.Game"
mc:Ignorable="d"
Title="MainWindow" Height="900" Width="900"
>
<Window.DataContext>
<game:Game/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="201*"/>
<ColumnDefinition Width="199*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="21*"/>
<RowDefinition Height="401*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Button x:Name="BtnOpen" Content="Pick Grid" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Click="BtnOpen_Click"/>
<TextBox x:Name="GridTextBox" HorizontalAlignment="Center" TextWrapping="NoWrap" VerticalAlignment="Center" Width="266" />
<Button x:Name="PickArtistBtn" Content="Pick Artist" HorizontalAlignment="Left" Margin="356,0,0,0" VerticalAlignment="Center" Click="PickArtistBtn_Click" RenderTransformOrigin="-0.135,0.647"/>
<TextBox x:Name="ArtistTextBox" HorizontalAlignment="Left" Margin="30,14,0,0" TextWrapping="NoWrap" VerticalAlignment="Top" Width="231" Grid.Column="1"/>
<Button x:Name="CreateGridBtn" Grid.Column="1" Content="Create Grid" HorizontalAlignment="Left" Margin="311,14,0,0" VerticalAlignment="Top" Click="CreateGridBtn_Click"/>
<Canvas Width="800" Height="800" Grid.ColumnSpan="2" Margin="49,15,51,27" Grid.Row="1" Background="DarkSeaGreen" Grid.RowSpan="2">
<ItemsControl Name="tilesItemsControl" ItemsSource="{Binding Tiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Rectangle
Width="15"
Height="15"
Fill="{Binding Color}"
Canvas.Left ="{Binding ConvertedXLoc}"
Canvas.Top="{Binding ConvertedYLoc}" />
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Name="ArtistItemsControl" ItemsSource="{Binding Artists}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Rectangle
Width="3.75"
Height="3.75"
Fill="Black"
Canvas.Left ="{Binding ConvertedXLoc}"
Canvas.Top="{Binding ConvertedYLoc}" />
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
<Grid/>
<Button Content="Button" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Row="2" VerticalAlignment="Center" Click="Button_Click"/>
</Grid>
So with the press of the button I added for testing purposes. It changes a value in the List and then the PropertyChanged method should detect that but it doesn't detect it it just skips it.
Question
So my basic question is, how do I detect the change of a property from objects out of the List of Artists.
OnPropertyChanged will only be executed when the property itself is changed. A new item in a list is not a property change. That's the reason why no updates happens.
Instead a List, try an ObservableCollection. An ObservableCollection implements an additional INotifyCollectionChanged which makes the UI able to react on changing items in the list.
I imagine that this is going to be flagged as a dduplicate but I am kind of stuck and not sure how to interpret other answers, or really know what I am doing wrong. Essentially my end problem is this:
I have a class that contains a field (a number) that can be changed. This class will be in an observable list that should contain a total of all the numbers from all elements in the observable collection. The total number should automatically change when the field of any member of the list is changed by the user. It is actually very similar to the problem posed here: Updating calculated total when a property on the underlying item in a list is changed - wpf. However, when I followed that solution and created a textbox that was bound to the total, the total was never changed. It seems also that the OnPropertyChanged event for the collection is never called to indicate that a property was changed in the underlying list. I think the problem is related to the fact that total_dose is never actually set but just has a get (from the link I provided). I am not sure how to implement the solutions I see on other posts. Would appreciate some guidance
CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.Specialized;
// https://stackoverflow.com/questions/51331010/updating-calculated-total-when-a-property-on-the-underlying-item-in-a-list-is-ch
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<string> sub_list { get; set; }
public MainWindow()
{
InitializeComponent();
structure temp_struct = new structure("Bladder");
structure_info_list.ItemsSource = temp_struct.fx_list;
this.DataContext = temp_struct;
}
}
public class structure : INotifyPropertyChanged
{
public structure(string name)
{
this.name = name;
fx_list = new ObservableCollection<fraction>();
fraction fx1 = new fraction(3);
fraction fx2 = new fraction(4);
fraction fx3 = new fraction(5);
fx_list.Add(fx1);
fx_list.Add(fx2);
fx_list.Add(fx3);
MessageBox.Show("Total: " + total_dose);
fx_list[0].fx_dose = 50;
MessageBox.Show("Total: " + total_dose);
}
private void fractions_changed_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
((fraction)item).PropertyChanged += fx_Changed;
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
((fraction)item).PropertyChanged -= fx_Changed;
}
}
}
void fx_Changed(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(fraction.fx_dose))
{
OnPropertyChanged(nameof(fx_list));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
MessageBox.Show("A property in the underlying list was changed: " + propertyName);
}
/*
public void calc_total_sum()
{
int total_sum_temp = 0;
foreach (fraction fx in fx_list)
{
total_sum_temp += fx.fx_dose;
}
total_sum = total_sum_temp;
}
*/
public string name { get; set; }
public ObservableCollection<fraction> fx_list { get; set; }
//public int total_sum { get; set; }
public int total_dose
{
get { return fx_list.Sum(x => x.fx_dose); }
set { }
}
}
public class fraction : INotifyPropertyChanged
{
private int _fx_dose;
public int fx_dose
{
get { return _fx_dose; }
set
{
_fx_dose = value;
this.calc_eq();
this.OnPropertyChanged("fx_dose");
//MessageBox.Show("FX DOSE PROP");
}
}
private int _eq;
public int eq
{
get { return _eq; }
set { _eq = value; }
}
public event PropertyChangedEventHandler PropertyChanged;
public fraction(int fx_dose)
{
this.fx_dose = fx_dose;
this.eq = fx_dose*2;
}
public void calc_eq()
{
this.eq = this.fx_dose * 2;
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
XAML
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<ItemsControl Name="structure_info_list">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Fraction "/>
<TextBox Text="{Binding Path=fx_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Total: "/>
<TextBlock Text="{Binding Path=total_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</StackPanel>
</Window>
Edit: I found the solution by looking at section 3 of this link
https://www.codeproject.com/Articles/28098/A-WPF-Pie-Chart-with-Data-Binding-Support#three
There are a couple if items.
First, you are setting the datacontext and the itemsource after you populate the list - this causes the notifications to not reach your binding. it is better to set these up in your XAML file.
Next, your property total_does does not call OnPropertyChanged("total_does").
Also, the datacontext is connected to the observable collection within structure. total_does is outside of the observable collection so your window will not see total_does or its notifications.
I made adjustmnts to show what I mean:
CS file:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public ObservableCollection<string> sub_list { get; set; }
private structure temp_struct;
public MainWindow()
{
InitializeComponent();
temp_struct = new structure("Bladder");
}
public structure Temp_Struct
{
get => temp_struct;
set
{
temp_struct = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string memberName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(memberName));
}
}
public class structure : INotifyPropertyChanged
{
private ObservableCollection<fraction> fxlist = new ObservableCollection<fraction>();
public structure(string name)
{
this.name = name;
fx_list = new ObservableCollection<fraction>();
fraction fx1 = new fraction(3);
fraction fx2 = new fraction(4);
fraction fx3 = new fraction(5);
fx_list.Add(fx1);
fx_list.Add(fx2);
fx_list.Add(fx3);
MessageBox.Show("Total: " + total_dose);
OnPropertyChanged("total_dose");
fx_list[0].fx_dose = 50;
MessageBox.Show("Total: " + total_dose);
OnPropertyChanged("total_dose");
}
private void fractions_changed_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
((fraction)item).PropertyChanged += fx_Changed;
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
((fraction)item).PropertyChanged -= fx_Changed;
}
}
}
void fx_Changed(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(fraction.fx_dose))
{
OnPropertyChanged(nameof(fx_list));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new propertyChangedEventArgs(propertyName));
MessageBox.Show("A property in the underlying list was changed: " + propertyName);
}
/*
public void calc_total_sum()
{
int total_sum_temp = 0;
foreach (fraction fx in fx_list)
{
total_sum_temp += fx.fx_dose;
}
total_sum = total_sum_temp;
}
*/
public string name { get; set; }
public ObservableCollection<fraction> fx_list
{
get => fxlist;
set
{
fxlist = value;
OnPropertyChanged();
}
}
//public int total_sum { get; set; }
public int total_dose
{
get { return fx_list.Sum(x => x.fx_dose); }
}
}
public class fraction : INotifyPropertyChanged
{
private int _fx_dose;
public int fx_dose
{
get { return _fx_dose; }
set
{
_fx_dose = value;
this.calc_eq();
this.OnPropertyChanged("fx_dose");
//MessageBox.Show("FX DOSE PROP");
}
}
private int _eq;
public int eq
{
get { return _eq; }
set { _eq = value; }
}
public event PropertyChangedEventHandler PropertyChanged;
public fraction(int fx_dose)
{
this.fx_dose = fx_dose;
this.eq = fx_dose * 2;
}
public void calc_eq()
{
this.eq = this.fx_dose * 2;
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML file:
<Window
x:Name="WinMain"
x:Class="DeluxMeasureStudies.Windows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DeluxMeasureStudies.Windows"
Title="MainWindow"
Width="800"
Height="450"
Foreground="White"
DataContext="{Binding Temp_Struct, ElementName=WinMain}"
Background="{StaticResource Normal.Window.Background}"
>
<StackPanel
Orientation="Vertical"
>
<ItemsControl Name="structure_info_list"
DataContext="{Binding Path=Temp_Struct, ElementName=WinMain}"
ItemsSource="{Binding Path=fx_list}">
<ItemsControl.ItemTemplate>
<DataTemplate
DataType="local:fraction"
>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Fraction "/>
<TextBox Text="{Binding Path=fx_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Total: "/>
<TextBlock Text="{Binding Path=total_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</StackPanel>
I have a problem with the listviewItem, is that when you change the data if they do it but they are not saved in the interface when you click on another item
This problem happens when binding the textbox to the listviewItem
MainPage.xaml
<Grid RequestedTheme="Light">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="818*" />
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBox
x:Name="titulo"
Grid.Row="0"
FontSize="40"
PlaceholderText="Ingresa tu titulo"
KeyDown="Titulo_KeyDown"
/>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<ListView
x:Name="listNotas"
Width="450"
Background="DimGray"
SelectionChanged="ListNotas_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate >
<StackPanel>
<TextBlock Text="{Binding title, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<RichEditBox
x:Name="editor"
Width="760"
HorizontalAlignment="Stretch" />
</StackPanel>
<GridView
Name="stpanel"
Grid.Row="2"
Height="50">
<TextBlock Text="" Name="Tester"/>
</GridView>
MainPage.xaml.cs
public string editpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "Notas.json" );
public ObservableCollection<Notes> Mynotes;
public MainPage()
{
this.InitializeComponent();
// Load data of Notas.json to Listview
LoadUpdate();
}
private void LoadUpdate()
{
using (StreamReader file = File.OpenText(editpath))
{
var json = file.ReadToEnd();
baseNotes mainnotes = JsonConvert.DeserializeObject<baseNotes>(json);
Mynotes = new ObservableCollection<Notes>();
foreach (var item in mainnotes.notes)
{
Mynotes.Add(new Notes { title = item.title });
}
listNotas.ItemsSource = null;
listNotas.ItemsSource = Mynotes;
listNotas.SelectedIndex = 0;
}
}
private void ListNotas_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string json = File.ReadAllText(editpath);
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
titulo.Text = jsonObj["notes"][listNotas.SelectedIndex]["title"];
}
private void Titulo_KeyDown(object sender, KeyRoutedEventArgs e)
{
#region
string json = File.ReadAllText(editpath);
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
int indice = listNotas.SelectedIndex;
jsonObj["notes"][indice]["title"] = titulo.Text;
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj);
File.WriteAllText(editpath, output);
// Show json file text in RicheditBox
editor.TextDocument.SetText(Windows.UI.Text.TextSetOptions.None, output);
//Problem
Binding myBinding = new Binding();
myBinding.Source = Mynotes[indice];
myBinding.Path = new PropertyPath("title");
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(titulo, TextBox.TextProperty, myBinding);
#endregion
}
Model: Notes.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
namespace Realtimejsonedit
{
public class Notes : INotifyPropertyChanged
{
public int created { get; set; }
//public string title { get; set; }
private string Title;
public string title
{
get { return Title; }
set {
Title = value;
NotifyPropertyChanged("title");
}
}
public string text { get; set; }
public int id { get; set; }
public int updated { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class baseNotes
{
public List<Notes> notes { get; set; }
}
}
as I say the problem as I am doing the binding but when executing ListNotas.SelectionChanged the values that were saved in the json file are changed, but they do not remain in the listviewitem, although the binding is in the Keydown event and not in ListNotas. SelectionChanged.
the problem:
https://i.imgur.com/IGcd8iz.gif
What I want to achieve:
https://i.imgur.com/KnkbQw9.gif
UWP - How to save ListViewItem state if the data source has changed?
The problem is that you set bind repeatedly in Titulo_KeyDown event. For your requirement, you could bind ListView SelectItem once. For more please refer the following steps:
ViewModel
public class ViewModel : INotifyPropertyChanged
{
public string editpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "Notas.json");
public ObservableCollection<Notes> Mynotes { get; set; }
public ViewModel()
{
LoadUpdate();
SetSelectIndex(0);
}
private void SetSelectIndex(int index)
{
SelectItem = Mynotes[index];
}
private void LoadUpdate()
{
using (StreamReader file = File.OpenText(editpath))
{
var json = file.ReadToEnd();
baseNotes mainnotes = JsonConvert.DeserializeObject<baseNotes>(json);
Mynotes = new ObservableCollection<Notes>();
foreach (var item in mainnotes.notes)
{
Mynotes.Add(new Notes { title = item.title });
}
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Notes _selectItem;
public event PropertyChangedEventHandler PropertyChanged;
public Notes SelectItem
{
get
{
return _selectItem;
}
set
{
_selectItem = value;
OnPropertyChanged();
}
}
}
Xaml
<Page.DataContext>
<local:ViewModel />
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="818*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TextBox
x:Name="titulo"
Grid.Row="0"
FontSize="40"
PlaceholderText="Ingresa tu titulo"
Text="{Binding SelectItem.title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="Titulo_TextChanged"
/>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<ListView
x:Name="listNotas"
Width="450"
Background="DimGray"
ItemsSource="{Binding Mynotes}"
SelectedItem="{Binding SelectItem, Mode=TwoWay}"
>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<RichEditBox
x:Name="editor"
Width="760"
HorizontalAlignment="Stretch"
/>
</StackPanel>
<GridView
Name="stpanel"
Grid.Row="2"
Height="50"
>
<TextBlock Name="Tester" Text="" />
</GridView>
</Grid>
Code behind (write the data to json)
public sealed partial class MainPage : Page
{
private dynamic jsonObj;
public string editpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "Notas.json");
public ObservableCollection<Notes> Mynotes;
public MainPage()
{
this.InitializeComponent();
string json = File.ReadAllText(editpath);
jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
}
private void Titulo_TextChanged(object sender, TextChangedEventArgs e)
{
#region
int indice = listNotas.SelectedIndex;
jsonObj["notes"][indice]["title"] = titulo.Text;
string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj);
editor.TextDocument.SetText(Windows.UI.Text.TextSetOptions.None, output);
File.WriteAllText(editpath, output);
#endregion
}
}
This is sample project.
I have Observable collection with MarketPrices , This observable collection I have bind to an ItemsControl as Below .
1) Now I don't want to show all Items in Observable Collection , want to show only items that user click Add and selected Pair (GBPJPY, USDGBP..) needs to show in Items Control.
2) If user changed item in Comobobox from GBPJPY to USDGBP , then the price( DataTemplate) of GBPJPY need to update USDGBP.
How can I achieve both conditions. Please note that below code doesn't have real-time update but in project I have relatime price update as well, so observable collection updates on price changes.
Code So Far
public class PriceModel : INotifyPropertyChanged
{
private double _askPrice;
private double _offerPrice;
private string _selectedPair;
public PriceModel()
{
Pairs = new ObservableCollection<string> {"GBPUSD", "GBPEUR", "USDGBP", "GBPJPY"};
}
public double AskPrice
{
get { return _askPrice; }
set
{
_askPrice = value;
OnPropertyChanged("AskPrice");
}
}
public double OfferPrice
{
get { return _offerPrice; }
set
{
_offerPrice = value;
OnPropertyChanged("OfferPrice");
}
}
public string SelectedPair
{
get { return _selectedPair; }
set
{
_selectedPair = value;
OnPropertyChanged(SelectedPair);
}
}
public ObservableCollection<string> Pairs { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
MarketPrices = new ObservableCollection<PriceModel>
{
new PriceModel {AskPrice = 1.60345, OfferPrice = 1.60335, SelectedPair = "GBPUSD"},
new PriceModel {AskPrice = 1.71345, OfferPrice = 1.71335, SelectedPair = "GBPEUR"},
new PriceModel {AskPrice = 1.23345, OfferPrice = 1.23335, SelectedPair = "USDGBP"},
new PriceModel {AskPrice = 1.34345, OfferPrice = 1.34335, SelectedPair = "GBPJPY"}
};
}
public ObservableCollection<PriceModel> MarketPrices { get; set; }
}
XAML
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding MarketPrices}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="5" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel AllowDrop="True" ClipToBounds="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding Pairs}" SelectedItem="{Binding SelectedPair}" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Margin="2" Text="Ask Price" />
<TextBlock Margin="2" Text="{Binding AskPrice}" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Margin="2" Text="Offer Price" />
<TextBlock Margin="2" Text="{Binding OfferPrice}" />
</StackPanel>
</Grid>
</Grid>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
If I understand your question correctly, you want to display a list of pairs in a ComboBox and the details for a Selected pair only but not for all pairs?
If that's the case, there are couple problems with the code.
PriceModel
You do not need a collection of all available pairs in your PriceModel class. Also, You do not need SelectedPair property in this class, may be your intention was to indicate the name of the pair, you could update your PriceModel to:
public class PriceModel : INotifyPropertyChanged
{
private double _askPrice;
private double _offerPrice;
private string _pair;
public PriceModel(string pair)
{
_pair = pair;
}
public string Pair
{
get { return _pair; }
}
public double AskPrice
{
get { return _askPrice; }
set
{
_askPrice = value;
OnPropertyChanged("AskPrice");
}
}
public double OfferPrice
{
get { return _offerPrice; }
set
{
_offerPrice = value;
OnPropertyChanged("OfferPrice");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindow.xaml.cs
You have a property named MarketPrices to hold the collection of Pairs, but no property to hold the Selected pair. Add a property named SelectedPair of type PriceModel. The Updated code would like this:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private PriceModel _selectedPair;
public MainWindow()
{
InitializeComponent();
DataContext = this;
MarketPrices = new ObservableCollection<PriceModel>
{
new PriceModel("GBPUSD") {AskPrice = 1.60345, OfferPrice = 1.60335, },
new PriceModel("GBPEUR") {AskPrice = 1.71345, OfferPrice = 1.71335, },
new PriceModel("USDGBP") {AskPrice = 1.23345, OfferPrice = 1.23335, },
new PriceModel("GBPJPY") {AskPrice = 1.34345, OfferPrice = 1.34335, }
};
}
public ObservableCollection<PriceModel> MarketPrices { get; set; }
public PriceModel SelectedPair
{
get { return _selectedPair; }
set
{
_selectedPair = value;
OnPropertyChanged("SelectedPair");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindow.xaml
You could just use ComboBox to display the list of available pairs and update your bindings for TextBoxes to refer SelectedPair.
Update XAML would look like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding Pairs}" SelectedItem="{Binding SelectedPair}" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Margin="2" Text="Ask Price" />
<TextBlock Margin="2" Text="{Binding SelectedPair.AskPrice}" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Margin="2" Text="Offer Price" />
<TextBlock Margin="2" Text="{Binding SelectedPair.OfferPrice}" />
</StackPanel>
</Grid>
</Grid>
Sample Output
I'm having trouble figuring out what the best solution is given the following situation. I'm using Prism 4.1, MEF, and .Net 4.0.
I have an object Project that could have a large number (~1000) of Line objects. I'm deciding whether it is better to expose an ObservableCollection<LineViewModel> from my ProjectViewModel and manually create the Line viewmodels there OR set the ListBox as it's own region and activate views that way.
I'd still want my LineViewModel to have Prism's shared services (IEventAggregator, etc.) injected, but I don't know how to do that when I manually create the LineViewModel. Any suggestions or thoughts?
EDIT: My initial thoughts:
Project:
public class Project
{
public List<Line> Lines { get; set; }
}
ProjectViewModel:
[Export(typeof(ProjectViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ProjectViewModel : NotificationObject, IRegionMemberLifetime
{
private Project _localProject;
/*
HERE WILL BE SOME PROPERTIES LIKE COST, PRICE THAT ARE CUMULATIVE FROM THE Lines
*/
public ObservableCollection<LineViewModel> Lines { get; private set; }
private readonly IEventAggregator _eventAggregator;
[ImportingConstructor]
public ProjectViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<ProjectLoaded>().Subscribe(SetupProject, false);
Lines = new ObservableCollection<LineViewModel>();
}
private void SetupProject(Project project)
{
_localProject = project;
foreach(var l in _localProject.Lines)
{
LineViewModel lvm = new LineViewModel(l);
lvm.PropertyChanged += // Some handler here
Lines.Add(lvm);
}
}
public bool KeepAlive
{
get { return false; }
}
}
LineViewModel:
public class LineViewModel : NotificationObject
{
private Line _localLine;
public decimal Cost
{
get { return _localLine.Cost; }
set
{
_localLine.Cost = value;
RaisePropertyChanged(() => Cost);
}
}
public LineViewModel(Line incoming)
{
_localLine = incoming;
}
}
I could be way off base here, maybe this is too simple, but does this help you at all? I created a quick project which demonstrated a few basics. If you need more info maybe I can use it to help you more.
Sample Application With Binding To "Lines"
View
<Window x:Class="WpfApplication1.LinesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="LinesView" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="247" d:DesignWidth="348" SizeToContent="WidthAndHeight" Width="350" Height="250">
<Window.Resources>
<DataTemplate x:Key="LineView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" MinWidth="50"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Line: " />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name}" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="X: " />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding X}" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Y: " />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Y}" />
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Total Cost" Margin="5" />
<TextBlock Text="{Binding Cost}" Margin="5" />
</StackPanel>
<ContentControl Name="contentControl1" Content="{Binding ElementName=listBox1, Path=SelectedItem}" ContentTemplate="{StaticResource LineView}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="105" Margin="5" />
<ListBox Height="234"
HorizontalAlignment="Center"
Name="listBox1"
VerticalAlignment="Center"
ItemsSource="{Binding Lines}"
ItemTemplate="{StaticResource LineView}" Width="152" Margin="5" />
</StackPanel>
</Window>
ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WpfApplication1.Models;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApplication1
{
public class LinesViewModel : INotifyPropertyChanged
{
public int Cost
{
get
{
return Lines.Sum(x => x.X + x.Y);
}
}
public ObservableCollection<Line> Lines
{
get;
private set;
}
public LinesViewModel()
{
Lines = new ObservableCollection<Line>();
Lines.Add(new Line()
{
Name = "Line1",
X = 0,
Y = 1
});
Lines.Add(new Line()
{
Name = "Line2",
X = 1,
Y = 1
});
Lines.Add(new Line()
{
Name = "Line3",
X = 2,
Y = 2
});
foreach(Line line in Lines)
{
line.XChanged += new EventHandler(lineChanged);
line.YChanged += new EventHandler(lineChanged);
}
Lines.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Lines_CollectionChanged);
}
private void Lines_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Line line in e.NewItems)
{
line.XChanged += new EventHandler(lineChanged);
line.YChanged += new EventHandler(lineChanged);
}
}
if (e.OldItems != null)
{
foreach (Line line in e.OldItems)
{
line.XChanged -= new EventHandler(lineChanged);
line.YChanged -= new EventHandler(lineChanged);
}
}
}
private void lineChanged(object sender, EventArgs e)
{
PropertyChanged(this, new PropertyChangedEventArgs("Cost"));
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
}
Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1.Models
{
public class Line
{
private int x;
private int y;
public String Name { get; set; }
public int X
{
get
{
return x;
}
set
{
x = value;
XChanged(this, EventArgs.Empty);
}
}
public int Y
{
get
{
return y;
}
set
{
y = value;
YChanged(this, EventArgs.Empty);
}
}
public event EventHandler XChanged = delegate { };
public event EventHandler YChanged = delegate { };
}
}
To manually create your LineViewModels with Prism/MEF you can use the container to resolve the dependencies, that is what it is for.
For example,
LineViewModel line = container.GetExportedValue<LineViewModel>();
See this link: Managing Dependencies: Resolving Instances With MEF
I'm sort of concerned about your design, is it really necessary for each of your lines to have a ViewModel and be created by the container and have dependencies injected? Is is possible that there could be one object which manages all of the lines and has those injected dependencies? Perhaps some sort of Repository Pattern might benefit you?
There can be considerable overhead if you are resolving thousands of objects through the container. The Prism book also mentions this may not be a good idea Considerations for using the container