Reactive UI Getting started with compelling example wont work - c#

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();
}
}

Related

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

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));
}

How can I access inherited members in a WPF window?

I am trying to create a base class for my windows in a WPF application but I cannot access their members in the derived classes. For example, here is the base window:
namespace MyApp.Windows
{
public class BaseWindow : Window
{
public int MyProp { get; set; }
}
}
And here is a window:
public partial class SomeWindow : BaseWindow
{
public SomeWindow()
{
InitializeComponent();
Loaded += SomeWindow_Loaded;
}
private void SomeWindow_Loaded(object sender, RoutedEventArgs e)
{
MyProp = do something;
}
}
If I leave it like this, the MyProp proerty works just fine but I get an error that InitializeComponent() is not recognized. Therefore, in the window xaml I change the x:Class as follows:
Before
<Window x:Class="MyApp.SomeWindow"
After
<Window x:Class="MyApp.Windows.BaseWindow"
Now, InitializeComponent() doesn't give me anymore issues but MyProp suddenly isn't recognized. Why?
In case it helps, what I want is to have all windows raise an event once they are loaded (the Loaded event is fired) and I don't want to write this code for every window I have, so I thought I could write this code in a base class, derive my windows from this and, well, have everything work.
Edit: Here's all the code.
BaseWindow.cs (no other xaml):
using System.Windows;
namespace MyApp.Windows
{
public class BaseWindow : Window
{
public int MyProp { get; set; }
}
}
MainWindow.xaml.cs
namespace MyApp.Windows
{
public partial class MainWindow : BaseWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow.xaml:
<myapp:BaseWindow x:Class="MyApp.Windows.BaseWindow"
xmlns:myapp="clr-namespace:MyApp.Windows"
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:MyApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</myapp:BaseWindow>
In order to change the base class of SomeWindow from Window to BaseWindow, you need to replace Window by BaseWindow wherever it occurs.
So
public partial class SomeWindow : Window
becomes
public partial class SomeWindow : BaseWindow
and
<Window x:Class="MyApp.Windows.SomeWindow" ...>
becomes
<myapp:BaseWindow x:Class="MyApp.Windows.SomeWindow"
xmlns:myapp="clr-namespace:MyApp.Windows" ...>
with the unavoidable XAML namespace prefix.
This is the BaseWindow class used in the example above:
namespace MyApp.Windows
{
public class BaseWindow : Window
{
public int MyProp { get; set; }
public BaseWindow()
{
Loaded += BaseWindow_Loaded;
}
private void BaseWindow_Loaded(object sender, RoutedEventArgs e)
{
}
}
}

Cannot create inherited usercontrol in WPF, base control "does not exist" in local namespace

I've tried to make a custom UserControl, "UserControl1" in WPF that inherits from a base class. Among others I get this error in the XAML:
Error XDG0008 The name "ControlBase" does not exist in the namespace "clr-namespace:Temp".
I also get an error at DesignHeight & Width
The ControlBase class was availible in VS autocompletion.
The ControlBase class is defined in the namespace Temp.
I've tried changing keywords for the base class, for example adding partial.
UserControl1.xaml:
<local:ControlBase x:Class="Temp.UserControl1"
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:Temp"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
</Grid>
</local:ControlBase>
UserControl1.xaml.cs:
namespace Temp
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : ControlBase
{
public UserControl1()
{
InitializeComponent();
}
}
}
ControlBase.cs:
using System.Windows.Controls;
namespace Temp
{
public class ControlBase : UserControl
{
public ControlBase() { }
}
}
I expected UserControl1 to inherit from ControlBase without compiler errors.
I don't know what I did, but it fixed itself.

Using viewmodellocator on projects without app.xaml declaration

I'm working on a add-in to Revit and want to use mvvm light. My problem is that the program runs my dll and I don't have a app.xaml to declare the singleton for viewmodellocator as a resource for the application, what is the best approach to declare this as a resource?
Revit runs my code as commands declared in separate classes in my solution that implements a IExternalCommand interface. Could I set this resource from code behind before calling my MainWindow? Or can I set it as a resource of my mainwindow.xaml?
EDITED
So far we have trided the code belov, but we get error on first time run on the command, but no error on the second time the command is used.
Sample code from the command class CheckerCommand.cs
[Transaction(TransactionMode.Manual)]
public class CheckerCommand : IExternalCommand
{
#region IExternalCommand Members Implementation
public Result Execute(ExternalCommandData revit, ref string message, ElementSet elements)
{
new ViewModelLocator();
MainWindow window = new MainWindow(revit);
try
{
WindowInteropHelper helper = new WindowInteropHelper(window)
{
Owner = Autodesk.Windows.ComponentManager.ApplicationWindow
};
window.ShowDialog();
return Result.Succeeded;
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
// Element selection cancelled.
return Result.Cancelled;
}
catch (Exception e)
{
message = e.ToString();
try
{
MessageBox.Show(message, "Fatal error");
window.Close();
}
catch
{
return Result.Failed;
}
return Result.Succeeded;
}
}
#endregion
}
Here is some sample code on MainWindow.xaml
<Window x:Class="QMChecker.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:QMChecker.Views"
xmlns:vm="clr-namespace:QMChecker.ViewModel"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mvvm="http://www.galasoft.ch/mvvmlight"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="QMChecker" Height="700" Width="1200">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/QMChecker;component/Resources/CombinedResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<vm:ViewModelLocator x:Key="Locator"/>
</ResourceDictionary>
</Window.Resources>
<Window.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}"/>
</Window.DataContext>
</Window>
Sample code from code-behind MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow(ExternalCommandData _revit)
{
try
{
InitializeComponent();
}
catch (Exception e)
{
throw e;
}
ServiceLocator.Current.GetInstance<MainViewModel>().Revit = _revit;
}
}
Sample code from ViewModelLocator.cs
public class ViewModelLocator
{
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
///
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<SpatialContainmentViewModel>();
SimpleIoc.Default.Register<SpatialContainmentDemandViewModel>();
SimpleIoc.Default.Register<RunChecksViewModel>();
SimpleIoc.Default.Register<SpatialContainmentParameterSummaryViewModel>();
}
public MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } }
public SpatialContainmentViewModel SpatialContainment { get { return ServiceLocator.Current.GetInstance<SpatialContainmentViewModel>(); } }
public SpatialContainmentDemandViewModel SpatialContainmentDemand { get { return ServiceLocator.Current.GetInstance<SpatialContainmentDemandViewModel>(); } }
public RunChecksViewModel RunChecks { get { return ServiceLocator.Current.GetInstance<RunChecksViewModel>(); } }
public SpatialContainmentParameterSummaryViewModel SpatialContainmentParameterSummary { get { return ServiceLocator.Current.GetInstance<SpatialContainmentParameterSummaryViewModel>(); } }
public static void Cleanup()
{
SimpleIoc.Default.Unregister<MainViewModel>();
SimpleIoc.Default.Unregister<SpatialContainmentViewModel>();
SimpleIoc.Default.Unregister<SpatialContainmentDemandViewModel>();
SimpleIoc.Default.Unregister<RunChecksViewModel>();
SimpleIoc.Default.Unregister<SpatialContainmentParameterSummaryViewModel>();
}
}
And I have to use ResourceDictionary on every UserControl
<UserControl.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator"/>
</ResourceDictionary>
</UserControl.Resources>
Old question, I know, but after some searching I haven't found an answer elsewhere. I just got this partially working, here's what I have:
MainWindow.xaml.cs
...
public MainWindow()
{
Resources.Add("Locator", new ViewModelLocator());
InitializeComponent();
}
...
MainWindow.xaml
<Window
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:AppleCMS.ModelHarvesterAddin"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Window.Resources>
<ResourceDictionary>
<local:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</ResourceDictionary>
</Window.Resources>
...
The rest is standard for MVVMLight. The key piece, I think, is the Resources.Add("Locator", new ViewModelLocator()); in the code-behind.
This works when running the addin. It doesn't look like MVVMLight's design-time data works yet though. I also haven't added multiple views yet, but I suspect I'll need the above in every view.

Changing base class for WPF page code behind

I have a simple class called CustomPage which inherits from Window:
public class CustomPage : Window
{
public string PageProperty { get; set; }
}
I want my MainWindow codebehind to inherit from CustomPage as follows:
public partial class MainWindow : CustomPage
{
public MainWindow()
{
InitializeComponent();
}
}
Unfortunately, I get the following error:
Partial declarations of 'WpfApplication1.MainWindow' must not specify different base classes
I can set x:Class to "WpfApplication1.CustomPage" in MainWindow.xaml, but then it appears I don't have access to the UI elements defined in MainWindow.xaml...
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
}
public class CustomPage : Window
{
public string PageProperty { get; set; }
}
<myWindow:CustomPage x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myWindow="clr-namespace:WpfApplication4"
Title="MainWindow" Height="800" Width="800">
<Grid>
</Grid>
</myWindow:CustomPage>
I hope this will help.
You need to update your xaml like this -
<local:CustomPage x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
</local:CustomPage>
Here, local is your namespace where CustomPage and MainWindow resides.
As the error suggested, you can't declare different base classes for partial declaration of class. So, in XAML too, you need to use the CustomPage instead of WPF Window

Categories

Resources