WPF UserControl inheriting another UserControl - c#

I am trying to inherit an usercontrol in WPF the way mentioned in How can a WPF UserControl inherit a WPF UserControl?
namespace DMS.Presentation
{
/// <summary>
/// Interaction logic for WorkSpaceViewControl
/// </summary>
public abstract class WorkSpaceViewControl : UserControl
{
public WorkSpaceViewControl()
{
InitializeComponent();
}
private void InitializeComponent()
{
}
}
}
And code doesn't give any error thus far. But when I inherit it in a new usercontrol:
namespace DMS.Presentation
{
/// <summary>
/// Interaction logic for AnimalWorkSpaceView.xaml
/// </summary>
public partial class AnimalWorkSpaceView : WorkSpaceViewControl
{
public AnimalWorkSpaceView()
{
InitializeComponent();
}
}
}
And it's XAML file is:
//I have tried both WorkSpaceViewControl:UserControl and UserControl:WorkSpaceViewControl here
<UserControl:WorkSpaceViewControl x:Class="DMS.Presentation.WorkSpaceViewControl"
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:DMS.Presentation"
xmlns:WorkSpaceViewControl="clr-namespace:DMS.Presentation"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
</UserControl:WorkSpaceViewControl>
I get a message that partial modifier doesn't exist. Another Partial Declaration of WorkSpaceViewControl exists. So how should I implement it and where have things gone wrong? My whole project is stuck due to this inheritance bottle-neck since January. Help will be really appreciated.

According to the answer you've referenced, your derived UserControl XAML should look more like this:
<local:WorkSpaceViewControl x:Class="DMS.Presentation.AnimalWorkSpaceView"
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:DMS.Presentation"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
</local:WorkSpaceViewControl>
You had declared two different XML namespaces, local and WorkSpaceViewControl, both referring to "clr-namespace:DMS.Presentation". You need just one of them (so I kept local, it being more idiomatic), and you need to use the namespace to qualify the type name WorkSpaceViewControl.
Thus, the XAML declaration starts as <local:WorkSpaceViewControl ...
In addition, the x:Class value for your derived class needs to be the derived class, not the base class. So instead of "DMS.Presentation.WorkSpaceViewControl", that should be set to "DMS.Presentation.AnimalWorkSpaceView" as shown above.

Related

Refactoring property name in code behind does not propagate to XAML file

I'm trying to refactor the property MyText to a new name HerText in the following solution:
MainWindow.xaml.cs
using System.Windows;
namespace resharper_refactoring_xaml
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyText = "Blabla";
DataContext = this;
}
public string MyText { get; set; }
}
}
MainWindow.Xaml
<Window x:Class="resharper_refactoring_xaml.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:resharper_refactoring_xaml"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBlock Text="{Binding Path=MyText}"></TextBlock>
</Grid>
</Window>
I right click on the property and select Refactor this > Rename. Then I type in a new name for the property, hit Next.
Unfortunately, only the references of MyText in the code-behind are renamed. References to MyText in the XAML file rename intact.
According to this question Resharper should be able to propagate refactorings to XAML files.
Why is the rename not propagating to the XAML file? Is there some sort of Resharper setting I might have overlooked?
The reason behind this seems to be that ReSharper cannot determine that the property name specified in the XAML markup refers to the property defined in the MainWindow class, if the DataContext property is set in code-behind.
Bindings refer to the DataContext of controls as source by default. If it is not detected, the link between the loose markup and the defining type is lost. I cannot tell if this is a bug in ReSharper or a general limitation.
However, there are two simple solutions to this issue that work for me:
Set a design time data context to the type that defines the property here MainWindow.
<Window ...
d:DataContext="{d:DesignInstance Type={x:Type local:MainWindow}}">
Set the data context via binding in XAML instead of code-behind.
<Window ...
DataContext="{Binding RelativeSource={RelativeSource Self}}">

Generic Window-Classes

I want to have a generic type of a Window.
However, if I implement the <R> into the class definition, it gives me errors, everywhere I reference on the xaml, e.g. at InitializeComponent(); or if I want to access any label or button.
The name 'InitalizeComponent' is not available in the current context
Probably, the reference/linking from the xaml to the code behind does not work properly.
Are there any suggestions, how I can achieve a correct linking to the xaml with generic window classes?
C#
namespace MyNamespace
{
public partial class Designer<R> : Window, IEventListener
where R : Region, new()
{
...
}
}
XAML
<Window
x:Class="MyNamespace.Designer"
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:local="clr-namespace:MyNamespace"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Designer"
Width="1600"
Height="1000"
mc:Ignorable="d">
...
</Window>
You need to provide x:TypeArguments directive:
<Window
x:Class="MyNamespace.Designer"
x:TypeArguments="src:Region"
...
</Window>

WPF Command binding to a static viewmodel

Firstly, I am new to WPF and MVVM, am trying hard to write well structured/separated code so please be kind.
I have created a user control and its own separate view model. In the view model I have an ICommand which relays to a method in the same viewmodel. I bind to this command in the XAML using System.Windows.Interactivity on an event like so:-
<UserControl x:Class="MyNamespace.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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:MyNamespace"
mc:Ignorable="d"
Height="300"
d:DesignHeight="300" d:DesignWidth="1500"
IsManipulationEnabled="True"
Background="{StaticResource BackgroundWhiteBrush}">
<Grid
d:DataContext="{x:Static local:MyControlDesignModel.Instance}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding MyViewModelCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
My code behind (which I'm trying to leave as empty as possible) looks like this:
namespace MyNamespace
{
/// <summary>
/// Interaction logic for MyControl.xaml
/// </summary>
public partial class MyControl : UserControl
{
public MyControl()
{
DataContext = ViewModelMyControl;
InitializeComponent();
}
}
}
I want to be able to use this control in several pages. I also want to be able to call a method in this view model (passing a parameter) from other view models to allow it to update itself from a datastore.
I used a DI container to provide a reference to the view model so that I can a) reference its data loading method from another place and b) set that to the DataContext in the code-behind (above).
The implementation of the DI container provides this as follows:
/// <summary>
/// A shortcut to access the <see cref="MyControlViewModel"/>
/// </summary>
public static MyControlViewModel ViewModelMyControl => Framework.Service<MyControlViewModel>();
With this DI referenced viewmodel on the DataContext, the event/command does not fire.
If I change the code behind to as follows, the event/command does fire but then I lose the static reference which I was trying to have to "hold" the data between pages. I seem to be able to have events or static reference but not both.
namespace MyNamespace
{
/// <summary>
/// Interaction logic for MyControl.xaml
/// </summary>
public partial class MyControl : UserControl
{
public MyControl()
{
DataContext = new MyControlViewModel();
InitializeComponent();
}
}
}
I think it has something to do with the ViewModel lifecycle or perhaps binding in general. I have been following a lot of guides and now find myself stuck.
How do I have event/commands firing and also maintain a reference to the user control's data between pages which use it?

Adding resources to an instance of WPF window

I'm making an AutoCAD .net program that has a WPF window as the interface. Currently the WPF interface is being referenced into the AutoCAD .net aplication and I'm calling the window from AutoCAD as follows.
public class Class1
{
public static WPFWindow.MainWindow mainWindow = new WPFWindow.MainWindow();
[CommandMethod("Launch", CommandFlags.Session)]
public void Launch()
{
Autodesk.AutoCAD.ApplicationServices.Application.ShowModalWindow(mainWindow);
}
}
This works fine until I start adding any form of resource to the WPF window I'm adding in. eg The following works until
<Window x:Class="WPFWindow.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:WPFWindow"
mc:Ignorable="d"
Title="Test" Height="450" Width="800"
WindowStyle="None"
AllowsTransparency="True"
>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Content="Press Me"/>
</Grid>
....I reference a static resource style for the window
WindowStyle="None"
AllowsTransparency="True"
Style="{StaticResource MainWindow}"
>
With the static resource when I run the "Launch" command in AutoCAD the program fails to find the static resource. I'm unsure how to get the instance of the WPFWindow to find the resource using C# code. As a test I added the WPFWindow as a reference to a WPF application and managed to get it to find the resource using the Pack URI
<ResourceDictionary Source="pack://application:,,,/WPFWindow;component/Themes/Styles.xaml"/>
Is there a C# equivalent of that I can use for the instance of the WPFWindow.MainWindow?
I managed to get it to work by adding the resources to the window I was referencing in its code behind files.
namespace WPFWindow
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.Resources.Source = new Uri(#"pack://application:,,,/WPFWindow;component/Themes/Styles.xaml"", UriKind.Absolute);
InitializeComponent();
}
}
}
I think this allowed the static resources to be loaded in before they were called for the window.
You cant use Staticresource in the root tag for external Resourcedictionaries. At time of Initialization the resource is not present. Linking it in ctor before calling InitializeComponent (as you did) does actually the same...
...
WindowStyle="None"
AllowsTransparency="True"
Style="{DynamicResource MainWindow}"
...
will work.

UWP inherit from a class inherited from UserControl

I am porting a Silverlight application to UWP Windows 10 app.
Large part of it has controls, inherited from a class, which inherits from UserControl.
base:
public abstract class PartBase : UserControl, IPart, IDisposable
concrete:
public sealed partial class MyPart : PartBase
its XAML:
<local:PartBase
I get compilation error : The name "PartBase" does not exist in the namespace ..
Is inheritance permitted in UWP ?
Your code should work. I've created your abstract base class and a new control based on that class.
<local:PartBase
x:Class="UWPTest.Controls.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWPTest.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<Button>Test</Button>
</Grid>
</local:PartBase>
Double check that the xmlns:local="using:UWPTest.Controls" is correct with the namespace PartBase is declared in. Then rebuild your solution and the error should go away (you will see the error if you don't rebuild).
On a page (e.g. MainPage) I can simply use the control:
<Page
x:Class="UWPTest.MainPage"
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:controls="using:UWPTest.Controls"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<controls:MyUserControl1 />
</Grid>
</Page>
Note the xmlns:controls pointing to the correct namespace. The designer will also give an error until you rebuild the app.
Everything builds here and the application runs, so if you still have the error after double checking all namepace declarations you'll have to put a repro online so we can check what else goes wrong.

Categories