WPF - Unable to set properties of dynamically added User Control via deserialization - c#

File des.txt --> this file is deserialized to xaml tree
<NewLabel NewText="some new text" LabelText="yes" xmlns="clr-namespace:WpfPractice;assembly=WpfPractice" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><av:Grid><av:Canvas><av:TextBox Width="100" Height="30">yes</av:TextBox></av:Canvas></av:Grid></NewLabel>
Mainwindow.xaml
<Window x:Class="WpfPractice.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfPractice"
Title="MainWindow"
Width="525"
Height="350">
<Grid Name="theGrid">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="1"
Width="50"
Height="25"
Click="Button_Click_2"
Content="Click" />
</Grid>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
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.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
namespace WpfPractice
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
NewLabel someNewLabel;
public MainWindow()
{
InitializeComponent();
someNewLabel = (NewLabel)DeserializeXaml(File.ReadAllText(#"D:\des.txt"));
theGrid.Children.Add(someNewLabel);
}
void Serialize()
{
NewLabel theNewLabel = new NewLabel();
theNewLabel.NewText = "some new text";
string xamlString = XamlWriter.Save(theNewLabel);
XmlReader reader = XmlReader.Create(new StringReader(xamlString));
UIElement copy = XamlReader.Load(reader) as UIElement;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
someNewLabel.LabelText = "new value";
someNewLabel.SetLabelValue("asdfsadgsafgreg");
//Serialize();
}
public object DeserializeXaml(string xaml)
{
StringReader stringReader = new StringReader(xaml);
XmlReader xmlReader = XmlReader.Create(stringReader);
return System.Windows.Markup.XamlReader.Load(xmlReader);
}
}
}
NewLabel.xaml
<UserControl x:Class="WpfPractice.NewLabel"
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"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid Name="theGrid">
</Grid>
NewLabel.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
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;
namespace WpfPractice
{
/// <summary>
/// Interaction logic for NewLabel.xaml
/// </summary>
public partial class NewLabel : UserControl, INotifyPropertyChanged
{
public static DependencyProperty NameProperty =
DependencyProperty.Register("NewText",
typeof(string),
typeof(NewLabel),
new PropertyMetadata(String.Empty));
public string NewText
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
private string _labelText = "yes";
public string LabelText
{
get
{
return _labelText;
}
set
{
_labelText = value;
OnPropertyChanged("LabelText");
}
}
Label theLabel;
public NewLabel()
{
InitializeComponent();
theLabel = new Label();
theLabel.Height = 30;
theLabel.Width = 100;
theLabel.Content = "old value";
Canvas theCanvas = new Canvas();
theCanvas.Children.Add(theLabel);
theGrid.Children.Add(theCanvas);
Binding b = new Binding("LabelText");
b.Source = this;
theLabel.SetBinding(TextBox.TextProperty, b);
theLabel.MouseDoubleClick += theLabel_MouseDoubleClick;
this.DataContext = this;
}
void theLabel_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("clicked!");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public void SetLabelValue(string val)
{
theLabel.Content = val;
}
}
}
Question:
Both these statements in MainWindow.xaml.cs
someNewLabel.LabelText = "new value";
someNewLabel.SetLabelValue("asdfsadgsafgreg");
do not work. In other words, I am unable to set the textbox property to "new value"

You are creating the binding in NewLable constructor, but then you load a new visual tree from a file which overrides the original one. That why you cant update the label nor by binding neither by setting the value directly because its not in the visual tree anymore.

Related

Datagrid stays Empty but ObservableCollection has values

Currently i am trying to learn WPF, but i have hit a brickwall with my current Problem, after many hours googling and trying to fix it on my own. I am trying to display the Model Province. I have found multiple similar Problems but i couldn't figure it out on my own. After having checked the Output there was no mention of any error. Currently the Window shows just the empty Model but no data even though the Observable Collection gets updated. So before i completely destroy my interest in WPF i am asking for help.
MyView
<Window x:Class="isnuaatest.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:isnuaatest"
xmlns:local1="clr-namespace:isnuaatest.Models"
xmlns:local2="clr-namespace:isnuaatest.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local2:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid>
<DataGrid ItemsSource="{Binding Provinces, UpdateSourceTrigger=PropertyChanged}">
</DataGrid>
</Grid>
<StackPanel Width="200" Margin="50">
<Button x:Name="OpenSaveFile" Click="OpenSaveFile_Click">OpenSaveFile</Button>
</StackPanel>
</Grid>
My View Model
using isnuaatest.Helper;
using isnuaatest.Models;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
namespace isnuaatest.ViewModel
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public ObservableCollection<Province> _province;
public ObservableCollection<Province> Provinces
{
get { return this._province; }
set
{
_province = value;
}
}
public MainWindowViewModel() : base()
{
this.Provinces = new ObservableCollection<Province>();
}
private string _savegamePath;
public string SavegamePath
{
get { return _savegamePath; }
set { _savegamePath = value; OnPropertyChanged("SavegamePath"); GetProvinces(_savegamePath);}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var savegamefile = this.PropertyChanged;
if (savegamefile != null)
savegamefile(this, new PropertyChangedEventArgs(propertyName));
}
public event EventHandler OnItemChanged;
public void GetProvinces(string path)
{
Reader reader = new Reader();
if (_savegamePath != null)
{
FileStream fs = File.OpenRead(path);
List<Province> listofProvinces = reader.ReadTextString(fs);
foreach (Province province in listofProvinces)
{
Provinces.Add(new Province()
{
Aristocrats = province.Aristocrats,
Artisans = province.Artisans
});
}
}
}
}
}
Code Behind
using isnuaatest.Helper;
using isnuaatest.Models;
using isnuaatest.ViewModel;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
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;
namespace isnuaatest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindowViewModel _vm = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
private void OpenSaveFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = false;
dynamic result = fileDialog.ShowDialog();
if (result == true)
{
_vm.SavegamePath = fileDialog.FileName;
}
}
}
}
My thinking is that maybe the Data Context wont update, because the data is in the Observable Collection. If this is true how can i update the Data Context, i already tried adding it in xaml to no avail.
Thanks
You actually create 3 different MainWindowViewModel objects - one in xaml and two in code behind. You can get rid of one in xaml, once in MainWindow constructor you set DataContext xaml-one is overridden.
But two objects in code-behind cause your problem - you load file into _vm object, but it's not the one that is held in DataContext.
To fix your problem use _vm for DataContext and not the new object:
public MainWindowViewModel _vm = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _vm;
}
Change your Provinces:
public ObservableCollection<Province> Provinces
{
get { return this._province; }
set
{
_province = value;
OnPropertyChanged("Provinces");
}
}

Binding on Dependency Property of UserControl

I'm trying to create UserControls to be able to reuse them later in the WPF application. I choose to build a small project to train myself, but I can't make it work.
The objective is to have a TextBox whose content will be sent as a Label Text with the click on a Button.
I've read and tried the solutions on those links :
XAML Binding on Dependency Property
Custom Dependency Properties
Simple Dependency Property and UserControl issues in C#
Add dependency property to control
But even the starting text I set in the constructor doesn't show up, and the button click does nothing at all.
Here are my files :
MyControl.xaml
<UserControl x:Class="WpfApplication1.MyControl"
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:WpfApplication1"
mc:Ignorable="d"
Name="control"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Text="{Binding TextBoxContent,ElementName=control}"/>
<Button Content="Print Entry" Grid.Row="1" Command="{Binding ButtonCommmand,ElementName=control}"/>
<Label Grid.Row="2" Content="{Binding LabelContent,ElementName=control}"/>
</Grid>
</UserControl>
MyControl.xaml.cs
using GalaSoft.MvvmLight.CommandWpf;
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;
namespace WpfApplication1
{
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
ButtonCommmand = new RelayCommand(Action);
}
public string TextBoxContent
{
get
{
return (string)GetValue(TextBoxContentProperty);
}
set
{
SetValue(TextBoxContentProperty, value);
}
}
public RelayCommand ButtonCommmand
{
get
{
return (RelayCommand)GetValue(ButtonCommandProperty);
}
set
{
SetValue(ButtonCommandProperty, value);
}
}
public string LabelContent {
get
{
return (string)GetValue(LabelContentProperty);
}
set
{
SetValue(LabelContentProperty, value);
}
}
public void Action()
{
LabelContent = TextBoxContent;
}
public static readonly DependencyProperty TextBoxContentProperty = DependencyProperty.Register("TextBoxContent", typeof(string), typeof(MyControl), new PropertyMetadata(""));
public static readonly DependencyProperty ButtonCommandProperty = DependencyProperty.Register("ButtonCommmand", typeof(RelayCommand), typeof(MyControl), new PropertyMetadata(null));
public static readonly DependencyProperty LabelContentProperty = DependencyProperty.Register("LabelContent", typeof(string), typeof(MyControl), new PropertyMetadata(""));
}
}
MainWindow.xaml
<Window x:Class="WpfApplication1.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:WpfApplication1"
xmlns:control="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<control:MyControl DataContext="{Binding customControl}" TextBoxContent="{Binding Text,Mode=TwoWay}" LabelContent="{Binding EndText,Mode=TwoWay}" ButtonCommmand="{Binding Command,Mode=TwoWay}"/>
</Grid>
</Window>
MainWindow.xaml.cs
using GalaSoft.MvvmLight.CommandWpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
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;
namespace WpfApplication1
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
MyControl customControl = new MyControl();
public MainWindow()
{
InitializeComponent();
Command = new RelayCommand(Action);
Text = "Testing... Testing... 1, 2, 3,...";
}
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
NotifyPropertyChanged();
}
}
private string endText;
public string EndText
{
get
{
return endText;
}
set
{
endText = value;
NotifyPropertyChanged();
}
}
private RelayCommand command;
public RelayCommand Command
{
get
{
return command;
}
set
{
command = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void Action()
{
EndText = Text;
}
private void NotifyPropertyChanged([CallerMemberName]string PropertyName = "")
{
if (!String.IsNullOrEmpty(PropertyName))
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
}
Thank you a lot for your help !
You are creating another instance of your UserControl in the code-behind of the window:
MyControl customControl = new MyControl();
What you want to do is to bind the properties of the UserControl that you have defined in your XAML to the properties of the window. For this to work you should set the DataContext of the window to itself:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Command = new RelayCommand(Action);
Text = "Testing... Testing... 1, 2, 3,...";
}
}
...and remove this from your XAML:
DataContext="{Binding customControl}"

OxyPlot PlotController

I am trying to disable auto panning on right button.
using OxyPlot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 OxyPlot.Wpf;
using PlotController.Properties;
namespace PlotController
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public class Chart
{
private OxyPlot.Series.LineSeries LS;
public PlotModel PlotModel {get;set;}
public Chart()
{
Random rnd = new Random();
PlotModel = new PlotModel();
LS = new OxyPlot.Series.LineSeries();
for (int i=0;i<100;i++)
{
LS.Points.Add(new DataPoint(i, rnd.Next(1,10)));
}
PlotModel.Series.Add(LS);
}
}
public partial class MainWindow : Window
{
Chart TChart;
public MainWindow()
{
TChart = new Chart();
OxyPlot.PlotController MyControl = new OxyPlot.PlotController();
MyControl.UnbindAll();
TestView = new PlotView();
TestView.Model = TChart.PlotModel;
TestView.Controller=MyControl;
DataContext = TChart;
InitializeComponent();
}
}
}
And xaml
* *
<Window x:Class="PlotController.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:oxy="http://oxyplot.org/wpf"
Title="MainWindow" Height="350" Width="525">
<Grid>
<oxy:PlotView Name="TestView" Model="{Binding PlotModel}" DefaultTrackerTemplate="{x:Null}" ></oxy:PlotView>
</Grid>
After unbinding all PlotCommand it still working.Why? How possible to disable panning on right button and enable on left button?
Try this in your MainWindow initialization code:
TestView.ActualController.UnbindAll();
TestView is the name of your PlotView defined in XAML.

Data Binding in MVVM WPF

I have little knowledge in MVVM pattern. My problem is the data does not get binded to the xaml controls, no error is there. The progressbar is still at 0.
HomepageViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using CSMS_MVVM.Models;
namespace CSMS_MVVM.ViewModels
{
class HomepageViewModel : INotifyPropertyChanged
{
BackgroundWorker _worker;
public int _progress=20;
public int Progress
{
get { return _progress; }
set {
_progress = value;
OnPropertyChanged(new PropertyChangedEventArgs("Progress"));
}
}
public void startBackgroundProcess()
{
_worker = new BackgroundWorker();
_worker.DoWork += new DoWorkEventHandler(worker_DoWork);
_worker.ProgressChanged += worker_Progress_Changed;
_worker.RunWorkerAsync();
}
private void worker_Progress_Changed(object sender, ProgressChangedEventArgs e)
{
Progress = e.ProgressPercentage;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
Progress = 20;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
#endregion
}
}
Homepage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
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 CSMS_MVVM.ViewModels;
namespace CSMS_MVVM.Views
{
/// <summary>
/// Interaction logic for Homepage.xaml
/// </summary>
public partial class Homepage : Page
{
HomepageViewModel hvm;
public Homepage()
{
InitializeComponent();
}
private void Page_Loaded_1(object sender, RoutedEventArgs e)
{
hvm = new HomepageViewModel();
hvm.startBackgroundProcess();
}
}
}
Homepage.xaml
<Page x:Class="CSMS_MVVM.Views.Homepage"
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:CSMS_MVVM.ViewModels"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="1000"
Title="Homepage" Loaded="Page_Loaded_1" Name="main">
<ProgressBar Name="pbStatus" Value="{Binding Path=Progress}" HorizontalAlignment="Center" Height="20" Margin="0,582,0,0" VerticalAlignment="Top" Width="300">
-----
<ProgressBar.Effect>
<DropShadowEffect Color="#FFB6B6B6" ShadowDepth="3" BlurRadius="15" Direction="310"/>
</ProgressBar.Effect>
</ProgressBar>
<TextBlock Text="{Binding Progress}" Margin="0,582,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" />
<Label Content="Loading ..." HorizontalAlignment="Center" Margin="0,607,0,0" VerticalAlignment="Top"/>
------
</Page>
Am i doing the correct coding? I searched the internet for an example but i did not understand them.
Thanks!
All bindings you set will bind to the DataContext if nothing else is specified.
private void Page_Loaded_1(object sender, RoutedEventArgs e)
{
hvm = new HomepageViewModel();
hvm.startBackgroundProcess();
this.DataContext = hvm;
}
Once you have your data context set to your viewmodel instance, it should work.
You can set the DataContext of the page in the code behind.
Another option is to create the ViewModel as a XAML resource, and set the data context of the child element via Data Binding:
<Page x:Class="CSMS_MVVM.Views.Homepage"
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:CSMS_MVVM.ViewModels"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="1000"
Title="Homepage" Loaded="Page_Loaded_1" Name="main">
<Page.Resources>
<!-- This creates the instance of the HomepageViewModel -->
<local:HomepageViewModel x:Key="HomepageViewModel" />
</Page.Resources>
<ProgressBar DataContext="{StaticResource HomepageViewModel}"
Value="{Binding Path=Progress}">
public Homepage()
{
InitializeComponent();
hvm = new HomepageViewModel();
this.DataContext=hvm;
}
Create view model object inside constructor.

WPF: DataBinding a PointCollection for a custom UIElement

I'm trying to make a WPF UIElement that does some special rendering.
The problem is that I can't get databinding to work for a PointCollection. Inside OnRender() of the GraphElement, the Points property is null, which doesn't make any sense to me.
class GraphElement : UIElement
{
public static readonly DependencyProperty PointsProperty = DependencyProperty.Register(
"Points",
typeof(PointCollection),
typeof(GraphElement),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
public PointCollection Points
{
get { return (PointCollection)GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
//Points is null
Debug.Assert(Points != null);
}
}
class TestViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private PointCollection _viewModelPoints;
public PointCollection ViewModelPoints
{
get { return _viewModelPoints; }
set
{
_viewModelPoints = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("ViewModelPoints"));
}
}
}
<Window x:Class="TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestApp"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas>
<local:GraphElement Points="{Binding Path=ViewModelPoints}"/>
</Canvas>
</Grid>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
namespace TestApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
var testViewModel = new TestViewModel();
testViewModel.ViewModelPoints = new PointCollection();
testViewModel.ViewModelPoints.Add(new Point(0.0, 0.0));
DataContext = testViewModel;
InitializeComponent();
}
}
}
Change the inheritance on GraphElement from UIElement to FrameworkElement (which in turn inherits UIElement). This is where you have the DataContext dp etc.
class GraphElement : FrameworkElement
{
//...
}
Copied your code into a sample project (changing UIElement to FrameworkElement) and Points is not null in OnRender. Uploaded the project here.

Categories

Resources