UserControl: This PlotModel is already in use by some other PlotView control - c#

I know this question has been posted already, but I don't understand the answers. In My case I have a project with only a UserControl:
<UserControl x:Class="SimpleOxyPlotUserControl.UserControl1View"
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:SimpleOxyPlotUserControl"
xmlns:oxy="http://oxyplot.org/wpf"
mc:Ignorable="d"
x:Name="uc1"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<oxy:PlotView Model="{Binding ElementName=uc1, Path=OxyPlotModel, Mode=TwoWay}"/>
</Grid>
</UserControl>
and its code behind:
using System.Windows;
using System.Windows.Controls;
using OxyPlot;
namespace SimpleOxyPlotUserControl
{
/// <summary>
/// Interaction logic for UserControl1View.xaml
/// </summary>
public partial class UserControl1View : UserControl
{
public UserControl1View() => InitializeComponent();
public PlotModel OxyPlotModel
{
get { return (PlotModel)GetValue(OxyPlotModelProperty); }
set { SetValue(OxyPlotModelProperty, value); }
}
public static readonly DependencyProperty OxyPlotModelProperty =
DependencyProperty.Register("OxyPlotModel", typeof(PlotModel), typeof(UserControl1View),
new PropertyMetadata(new PlotModel()));
}
}
Then I have another project with a simple WPF App and its MainWindow.xaml:
<Window x:Class="SimpleOxyPlotUserControlApp.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:simpleOxyPlotUserControl="clr-namespace:SimpleOxyPlotUserControl;assembly=SimpleOxyPlotUserControl"
Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<simpleOxyPlotUserControl:UserControl1View/>
<simpleOxyPlotUserControl:UserControl1View Grid.Row="1"/>
</Grid>
</Window>
and its code behind:
using System.Windows;
namespace SimpleOxyPlotUserControlApp.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
I receive the error message "InvalidOperationException: This PlotModel is already in use by some other PlotView control."
I know this is, because each Oxy PlotModel can only be connected to exactly one Oxy PlotView. But why does it not create a new Oxy PlotView and PlotModel each time, when I insert my UserControl? And how can I ensure that it does so?

OxyPlotModelProperty is registered with new PlotModel() default value in PropertyMetadata. but OxyPlotModelProperty is static so you get the same PlotModel instance for all UserControl1View instances.
fix it by creating PlotModel in constructor:
public partial class UserControl1View : UserControl
{
public UserControl1View()
{
InitializeComponent();
SetLocalValue(OxyPlotModelProperty, new PlotModel());
}
public PlotModel OxyPlotModel
{
get { return (PlotModel)GetValue(OxyPlotModelProperty); }
set { SetValue(OxyPlotModelProperty, value); }
}
public static readonly DependencyProperty OxyPlotModelProperty =
DependencyProperty.Register("OxyPlotModel", typeof(PlotModel), typeof(UserControl1View),
new PropertyMetadata(null));
}

Related

OxyPlot - WPF PlotView does not update property

I have a PlotView that has the height binds to the property ModelHeight in the view model.
MainWindow.xaml
<oxy:PlotView x:Name="IOPlot" Model="{Binding IOPlotModel}" Height="{Binding ModelHeight, UpdateSourceTrigger=PropertyChanged}" Width="630">
ViewModel.cs
private double modelheight = 300;
public double ModelHeight {
get{return modelheight;}
set { modelheight = value;
RaisePropertyChanged("ModelHeight");
RaisePropertyChanged("IOPlotModel");
this.IOPlotModel.InvalidatePlot(false);
}
}
The problem is that: it doesn't update the height with the data binding! The height only changes once during the startup of the PlotModel. It seems like the height is fixed (IOPlotModel.Height always equals 300 even though ModelHeight changed).
Does anyone know how to fix this issue?
In this minimal example view and view model are the same class MainWindow, so the DataContext is set to this inside the constructor. Usually it should be the view model in a MVVM architecture.
XAML:
<Window x:Class="PlotTest.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:oxyplot="http://oxyplot.org/wpf"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox x:Name="HeightTextBox"
Width="200"
TextChanged="HeightTextBox_TextChanged" />
<oxyplot:PlotView Grid.Row="1"
Model="{Binding MyModel, UpdateSourceTrigger=PropertyChanged}"
Height="{Binding ModelHeight, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Window>
Code behind:
using OxyPlot;
using System.ComponentModel;
using System.Windows;
namespace PlotTest
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
private double modelheight = 300;
public MainWindow()
{
this.DataContext = this;
this.MyModel = new PlotModel() { Background = OxyColors.AliceBlue };
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public double ModelHeight
{
get { return modelheight; }
private set
{
modelheight = value;
this.RaisePropertyChanged("ModelHeight");
}
}
public PlotModel MyModel { get; private set; }
private void HeightTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
if (double.TryParse(this.HeightTextBox.Text, out double height))
{
this.ModelHeight = height;
}
}
private void RaisePropertyChanged(string propertyName = "")
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Reactive UI Getting started with compelling example wont work

I did this many times, but now it just doest work.
I am following this example:
https://www.reactiveui.net/docs/handbook/routing/
I have my MainWindow.xaml.cs
using ReactiveUI;
namespace KardexTerminal_WPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : ReactiveWindow<MainViewModel>
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow.xaml
<rxui:ReactiveWindow x:Class="KardexTerminal_WPF.MainWindow"
xmlns:rxui="https://reactiveui.net"
x:TypeArguments="local:MainViewModel"
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:KardexTerminal_WPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</rxui:ReactiveWindow>
MainViewModel:
using ReactiveUI;
namespace KardexTerminal_WPF
{
public class MainViewModel : ReactiveObject, IScreen
{
public MainViewModel()
{
Router = new RoutingState();
}
public RoutingState Router { get; }
}
}
Simple as documentation suggest. This is completely new project and have only ReactiveUI and ReactiveUI.WPF packages installed.
But I am getting those error:
I will be glad for any help, if anyone knows what is the issue.
EDIT 1:
If I implement IViewFor, then it works.
I have tried suggestions from comments on view usercontrol:
<rxui:ReactiveUserControl x:Class="KardexTerminal_WPF.Views.LoginView"
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:KardexTerminal_WPF.Views"
mc:Ignorable="d"
xmlns:vm="clr-namespace:KardexTerminal.ViewModels;assembly=KardexTerminal"
x:TypeArguments="vm:LoginViewModel"
xmlns:rxui="https://reactiveui.net"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
</Grid>
</rxui:ReactiveUserControl>
namespace KardexTerminal_WPF.Views
{
/// <summary>
/// Interaction logic for LoginView.xaml
/// </summary>
public partial class LoginView
{
public LoginView()
{
InitializeComponent();
}
}
}
But that makes those errors, I am not sure what is wrong:
I am using those packages:
EDIT 2:
Answer below from #mm8 helped to make the program compile.
ReactiveUI has wrong documentation and should be fixed:
https://www.reactiveui.net/docs/handbook/routing/
But there is stil error, which I cannot seem to get rid off. I will proceed with that at GitHub issue.
The namespace is http://reactiveui.net (and not https://...):
xmlns:rxui="http://reactiveui.net"
Besides this, your code-behind class should inherit from ReactiveUserControl<LoginViewModel> since this is the base class you have specified in the XAML markup:
public partial class LoginView : ReactiveUserControl<LoginViewModel>
{
public LoginView()
{
InitializeComponent();
}
}
I've got similar problems using the ReactiveUserControl class. I've found 2 workaround for this
1)Create a base class for your window that inherit from ReactiveWindow than let MainWindow inherit from that class
public class MainWindowBase : ReactiveWindow<MainViewModel> { }
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
}
Than in your xaml
<local:MainWindowBase x:Class="YourNameSpace.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:YourNameSpace"
mc:Ignorable="d"
Title="" Height="600" Width="1000" >
2)Implement manually the IViewFor<T>
public partial class MainWindow : Window, IViewFor<MainViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel", typeof(MainViewModel), typeof(MainWindow));
public MainViewModel ViewModel
{
get { return (MainViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (MainViewModel)value;
}
public MainWindow()
{
InitializeComponent();
}
}
EDIT: based on the comment of Glenn Watson I've updated the answer but for completeness I'll add here the previous answer that will be usefull when working on the UWP
public class MainWindowBase : ReactiveWindow<MainViewModel> { }
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow :MainWindowBase
{
public MainWindow()
{
InitializeComponent();
}
}

WPF: How can I reload the Custom Property's Default Value with it's Design-Time-Value from the parent XAML?

I am writing a User Control named "GridAndChart" that can be filled with values at Design-Time just like this:
<local:GridAndChart HorizontalAlignment="Left"
VerticalAlignment="Top" Width="660"
Height="342"
Margin="28,29,0,0"
NameX="Auslastung in %"
NameY="Wirkungsgrad in %"
MinValueX="0"
MaxValueX="100"
MinValueY="0"
MaxValueY="100"
TitleOfChart="Kennlinie Wirkungsgrad"
Xvals='12,323,43,55,65,7'
Yvals='60,99,99,99,99,99'
/>
Most of the Properties you can see there (Like TitleOfChart, Xvals,...) I defined in the Code-Behind-File of my User-Control as Dependency-Properties.
My Problem is that only those Dependency-Properties are displayed correctly in my Test-Window, that are bound in the UserControl-XAML and therefore invoked by the initializeComponent(), like for example TitleOfChart. By displayed correctly I mean: Display of the Design-time-value from the XAML where I include my UserControl. The other dependency properties don't display correctly because they show only their default value.
From my example you will see that the Evaluation of my dummy-calculations will happen with the default values of the Dependency Properties. Not, after that they got their "Design-Time-Values", read out from the Main.xaml.
Thankyou for your help!
EDIT: Reproducible Code (4 Files)
File 1 and 2: The Window that uses the Control and it's Code-Behind
MainWindow.xaml
<Window x:Class="MinimalReproducibleExample.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:MinimalReproducibleExample"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:SimpleUserControl Working="I defined this Text at Design time" NotWorking="1,2,3,4"/>
</Grid>
</Window>
MainWindow.xaml.cs (I left it empty)
using ...
namespace MinimalReproducibleExample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
File 3 and 4: The User-Control and it's Code-Behind
SimpleUserControl.xaml
<UserControl x:Class="MinimalReproducibleExample.SimpleUserControl"
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:MinimalReproducibleExample"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="TextBox1XAML" />
<TextBox Grid.Row="1" Name="TextBox2XAML" />
</Grid>
</UserControl>
SimpleUserControl.xaml.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;
namespace MinimalReproducibleExample
{
public partial class SimpleUserControl : UserControl
{
public SimpleUserControl()
{
InitializeComponent();
string notWorking = NotWorking;//just to show that there happens some calculation with the values
int a = Convert.ToInt32(notWorking.ElementAt(0)); //before they are displayed
int b = Convert.ToInt32(notWorking.ElementAt(1));
int c = a + b;
TextBox2XAML.Text = c.ToString();
}
public string Working
{
get { return GetValue(WorkingProperty).ToString(); }
set { SetValue(WorkingProperty, value); }
}
public static readonly DependencyProperty WorkingProperty = DependencyProperty.Register(nameof(Working), typeof(string), typeof(SimpleUserControl), new PropertyMetadata("The default is working.", (s, e) => (s as SimpleUserControl).TextBox1XAML.Text = (string)e.NewValue));
public string NotWorking
{
get { return GetValue(NotWorkingProperty).ToString(); }
set { SetValue(NotWorkingProperty, value); }
}
public static readonly DependencyProperty NotWorkingProperty = DependencyProperty.Register(nameof(NotWorking), typeof(string), typeof(SimpleUserControl), new PropertyMetadata("The default is also working.", (s, e) => (s as SimpleUserControl).NotWorking = (string)e.NewValue));
}
}
In your MCVE if you put the code to the Loaded event handler of your usercontrol, then all will work as expected. See example:
Usercontrol:
public partial class SimpleUserControl : UserControl
{
public string SimpleTxtProp { get; set; } = "AAA";
public SimpleUserControl()
{
//Constructor being called from InitializeComponent() of parent element. All properties are initialized with values from code behind,
//after object creation is finished, it's property will be initialized with values set in parent element for this control.
InitializeComponent();//Content of control being initialized: constructor -> InitializeComponent()
var isAAA = SimpleTxtProp == "AAA";//true
Loaded += (o, e) =>
{
var isBBB = SimpleTxtProp == "BBB"; //true
};
}
}
MainWindow:
<local:SimpleUserControl SimpleTxtProp="BBB"/>
It doesn't matter whether you consider dependency or simple property.
InitializeComponent() of MainWindow does
trigger the instantiation of SimpleUserControl, hence constructor
with default values/values from code behind being called,
then the properties of the created object being set.
So once an istance of "SimpleUserControl" is loaded, it has the values, which was set in XAML of MainWindow.

Viewmodel doesn't exist in namespace

I'm sorry if this is a stupid question or doesn't even fall under what I'm asking, but I'm new to WPF and I can't seem to get the hang of it. Right now I'm doing something akin to https://www.c-sharpcorner.com/article/use-inotifypropertychanged-interface-in-wpf-mvvm/ and I've run into a problem. When I try to execute my code:
namespace DPS_Calculator_Prototype
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow() {
InitializeComponent();
}
}
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChange(string propertyName) {
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
public class Calculator: NotifyPropertyChanged
{
private string _damage;
public string Damage {
get { return _damage; }
set {
_damage = value;
RaisePropertyChange("Damage");
}
}
}
namespace UseOf_INotifyPropertyChanged
{
public class MainWindowViewModel : Calculator
{
public MainWindowViewModel() {
Damage = "7";
}
}
}
}
I get the error that "The type or namespace name 'ViewModel' does not exist in the namespace 'DPS_Calculator_Prototype.UseOf_INotifyPropertyChanged' (are you missing an assembly reference?)"
and
"The name "MainWindowViewModel" does not exist in the namespace 'clr-namespace:DPS_Calculator_Prototype.UseOf_INotifyPropertyChanged.ViewModel'."
and
"The type 'VM:MainWindowViewModel' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built."
I get the first error twice, once in MainWindow.g.cs and another in MainWindow.xaml. The other two are all in MainWindow.XAML If anyone can tell me what I'm doing wrong then that would be great. Here's the XAML file:
<Window x:Class="DPS_Calculator_Prototype.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:VM="clr-namespace:DPS_Calculator_Prototype.UseOf_INotifyPropertyChanged.ViewModel"
xmlns:local="clr-namespace:DPS_Calculator_Prototype"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<VM:MainWindowViewModel x:Name="VMMainWindow">
</VM:MainWindowViewModel>
</Window.DataContext>
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap"
Text="{Binding Damage}" VerticalAlignment="Top" Width="120"
Margin="78,28,0,0" TextChanged="TextBox_TextChanged"/>
</Grid>
</Window>
That's one of the worst "copy and paste" jobs I've ever seen guy...
I don't know where to start.
Just to run the application you MUST:
change the namespace VM as follows;
xmlns:VM="clr-namespace:DPS_Calculator_Prototype.UseOf_INotifyPropertyChanged"
DPSCalculatorPrototype.ViewModel doesn't exist.
The TextBox_TextChanged doesn't exist inside the codebehind of the window. You must add the method
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
//Do your stuffs
}
in the MainWindow class.
In order to avoid headaches to you or who is reading your code, you
SHOULD
use one .cs file for each class.
Avoid to nest namespaces inside the same .cs file and create a folder tree that replicates the namespace structure. In your snippet just create a UseOf_INotifyPropertyChanged folder inthe root and create the MainWindowViewModel class inside that.
The purpose of a namespace must be clear reading the code. Create a DPS_Calculator_Prototype.ViewModels and put all application viewmodel inside it.
I just tried using different namespaces and keep them more simple. And it works.
DPSCalculatorPrototype.ViewModel
namespace DPSCalculatorPrototype.ViewModel
{
public class MainWindowViewModel : Calculator
{
public MainWindowViewModel()
{
Damage = "7";
}
}
}
DPSCalculatorPrototype
namespace DPSCalculatorPrototype
{
public class Calculator : NotifyPropertyChanged
{
private string _damage;
public string Damage
{
get { return _damage; }
set
{
_damage = value;
RaisePropertyChange("Damage");
}
}
}
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChange(string propertyName)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
MainWindow.xaml
<Window x:Class="DPSCalculatorPrototype.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:VM="clr-namespace:DPSCalculatorPrototype.ViewModel"
xmlns:local="clr-namespace:DPSCalculatorPrototype"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<VM:MainWindowViewModel x:Name="VMMainWindow"></VM:MainWindowViewModel>
</Window.DataContext>
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="{Binding Damage}" VerticalAlignment="Top" Width="120" Margin="78,28,0,0" TextChanged="TextBox_TextChanged" />
</Grid>
</Window>
MainWindow.xaml.cs
namespace DPSCalculatorPrototype
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
}
}
}
The reason you are seeing these errors is that WPF is looking in the namespaces mentioned and cannot seem to find what you're looking for. If you take a look at your XAML code you can see the line that says:
xmlns:VM="clr-namespace:DPS_Calculator_Prototype.UseOf_INotifyPropertyChanged.ViewModel"
This is what is declaring to use the namespace, so we need to point it to the correct area. Change your XAML to look like the following:
<Window x:Class="DPS_Calculator_Prototype.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:VM="clr-namespace:DPS_Calculator_Prototype.UseOf_INotifyPropertyChanged"
xmlns:local="clr-namespace:DPS_Calculator_Prototype"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<VM:MainWindowViewModel x:Name="VMMainWindow">
</VM:MainWindowViewModel>
</Window.DataContext>
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="
{Binding Damage}" VerticalAlignment="Top" Width="120" Margin="78,28,0,0"
TextChanged="TextBox_TextChanged"/>
</Grid>
</Window>
You were getting these errors because you had "ViewModel" in the namespace declaration, and this namespace doesn't exist, and as such, nothing exists in it.

Passing Page1 Text to Page 2 WPF MVVM

I have been all over the internet looking for a clear answer and cannot find one. I have created Window Forms apps in the past, and decided to give WPF a try. I am hoping I don't have to move back to WinForms, but cannot figure out the simplest tasks.
How do I pass text in Page1's Textbox to Page2's TextBox.
I apologize if this is a duplicate, but I cannot find a clear answer anywhere. Most beginner mvvm tutorials seem to stick to one page apps.
MainWindo.xaml
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Frame Source="/Page1.xaml"/>
</Grid>
</Window>
Page1 Xaml:
<Page x:Class="WpfApp3.Page1"
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:WpfApp3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1"
xmlns:vm="clr-namespace:WpfApp3">
<Page.DataContext>
<vm:Page1ViewModel/>
</Page.DataContext>
<Grid>
<StackPanel>
<TextBlock Margin="20" FontSize="36">Welcome Home</TextBlock>
<TextBox x:Name="UserName" Margin="10 0 10 0" Text=""/>
<Button x:Name="Next" Margin="10 10" Content="Next" Click="Next_Click"/>
</StackPanel>
</Grid>
</Page>
Page1 Code-Behind:
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp3
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void Next_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(
new Uri("/Page2.xaml", UriKind.Relative));
}
}
}
Page1 ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp3
{
class Page1ViewModel : Notifier
{
private string username;
public string UserName
{
get { return username; }
set
{
username = value;
OnPropertyChanged("UserName");
}
}
}
}
Page2 Xaml:
<Page x:Class="WpfApp3.Page2"
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:WpfApp3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page2"
xmlns:vm="clr-namespace:WpfApp3>
<Page.DataContext>
<vm:Page2ViewModel/>
<Page.Data.Context>
<Grid>
<StackPanel>
<TextBlock Margin="10">Hello there: </TextBlock>
<TextBox x:Name="TextBox_Name" Margin="10" Text="{Binding UserName}"/>
</StackPanel>
</Grid>
</Page>
Page2 Code-behind:
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp3
{
/// <summary>
/// Interaction logic for Page2.xaml
/// </summary>
public partial class Page2 : Page
{
public Page2()
{
InitializeComponent();
}
}
}
Page2 View Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp3
{
class Page2ViewModel : Notifier
{
private string textbox_name;
public string TextBox_Name
{
get { return textbox_name; }
set
{
textbox_name = value;
OnPropertyChanged("TextBox_Name");
}
}
}
}
first of all you don't need to move back to WinForms: you can avoid MVVM alltogether and use the traditional code-behind coding model you know even with WPF. I'd suggest doing so for your first WPF applications if you don't feel at ease with MVVM.
As for your problem, a solution could be to use static properties for common values storage.
public class MyCommonValues
{
public static string SharedText { get; set; }
}
class Page1ViewModel : Notifier
{
private string username;
public string UserName
{
get { return username; }
set
{
username = value;
OnPropertyChanged("UserName");
OnUserNameChanged(); // added to your code
}
}
// following is an addition to your code
void OnUserNameChanged()
{
MyCommonValues.SharedText = UserName;
}
}
class Page2ViewModel : Notifier
{
// following is an addition to your code
public Page2ViewModel()
{
TextBox_Name = MyCommonValues.SharedText;
}
private string textbox_name;
public string TextBox_Name
{
get { return textbox_name; }
set
{
textbox_name = value;
OnPropertyChanged("TextBox_Name");
}
}
}

Categories

Resources