Adding derived UserControls to List<> in Wpf - c#

Im trying to create a list of wpf user controls and then set the mainwindows content to the usercontrol at runtime.
Since all UserControls will also share interfaces I want to build them from a derived window class as such:
public class BaseControl : UserControl, IControlState
public string ControlName
{
get
{
return this.GetType().Name;
}
}
public void UseState(object parameters)
{
throw new NotImplementedException();
}
}
Class derived from UserControl
public partial class Buglist : UserControl
{
public Buglist()
{
InitializeComponent();
}
}
Class derived from my BaseControl
public partial class Login : BaseControl
{
public Login()
{
InitializeComponent();
}
}
The Login xaml to allow Visual Studio designer to recognize a designable component
<MyType:BaseControl x:Class="BugAnalyzer.Controls.Login"
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:BugAnalyzer.Controls"
xmlns:MyType="clr-namespace:BugAnalyzer.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="112,72,0,0" TextWrapping="Wrap" Text="login" VerticalAlignment="Top"/>
</Grid>
In my main window I want to be able to add these controls to a list and then be able to access shared properties such as ControlName.
public partial class MainWindow : Window
{
List<UserControl> uclist = new List<UserControl>();
List<BaseControl> bcList = new List<BaseControl>();
public MainWindow()
{
InitializeComponent();
Buglist UserControlDerivedWindow = new Buglist();
Login BaseControlDerivedWindow = new Login();
uclist.Add(UserControlDerivedWindow); //Works
bcList.Add(BaseControlDerivedWindow); //Fails
}
why can I add the class derived from UserControl to a list UserControls
but not a class derived from BaseControl to a list of BaseControls?

Strangely I have solved this though I not sure what the root issue was
For clarity in the question I wrote
Login BaseControlDerivedWindow = new Login();
but the actual code was
Login login = new Login();
which caused the compiler to issue something like "
Cannot covert from Program.Controls.Login to Program.Controls.BaseControl"
after I changed the code for clarity it compiled and then let me rename the Login instance back to login and compiled no issues again.

Related

DialogWindow in Prism does not show my window

I need to open a dialog window when I open a module.
In my module I register WindowA and I want to show it in method OnInitialize() of the module. It looks like this.
public class TestModule : IModule
{
IDialogWindow _dialogWindow;
public TestModule(IContainerProvider containerProvider, IDialogWindow dialogWindow)
{
_dialogWindow = dialogWindow;
}
public void OnInitialized(IContainerProvider containerProvider)
{
_dialogWindow.Show();
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<WindowA>();
}
}
My window
<Window x:Class="FirstModule.Views.WindowAView"
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:prism="http://prismlibrary.com/"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:local="clr-namespace:FirstModule.Views"
mc:Ignorable="d"
Title="WindowA" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="Button"/>
</Grid>
</Window>
and View model for this
class WindowAViewModel : IDialogAware
{
public WindowAViewModel()
{
}
public string Title { get; }
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
}
public void OnDialogOpened(IDialogParameters parameters)
{
}
}
Also I implemented IDialogWindow
public partial class WindowAView : Window, IDialogWindow
{
public WindowAView()
{
InitializeComponent();
}
public IDialogResult Result { get; set; }
}
But instead of WindowAView a small window is shown with Width and Height equal to 0.
Could you please explain what I did wrong?
I think you misunderstood the dialog service, from the documentation:
Your dialog view is a simple UserControl that can be designed anyway you please. The only requirement it has a ViewModel that implements IDialogAware set as it's DataContext.
The dialog view is a UserControl that is shown in a dialog host. Prism uses a standard WPF window as default dialog host, but you can create your own by implementing the IDialogWindow interface and registering it. In Prism 7, there was only one dialog host for all. Since Prism 8, you can use the same dialog host for all dialog views or different dialog hosts as you want.
It's very common to be using a third-party control vendor such as Infragistics. In these cases, you may want to replace the standard WPF Window control that hosts the dialogs with a custom Window class such as the Infragistics XamRibbonWindow control.
In this case, just create your custom Window, and implement the IDialogWindow interface: [...] Then register your dialog window with the IContainerRegistry. [...] If you have more than one dialog window you would like to use as a dialog host, you register multiple dialog windows with the container by specifying a name for the window.
You inject the IDialogWindow into the module constructor, which is not your WindowAView, but simply the default dialog host window, which is empty, as there is no content to host. What you should do instead is define your view as a UserControl and adapt your WindowAViewModel accordingly.
<UserControl x:Class="FirstModule.Views.AView"
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:prism="http://prismlibrary.com/"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:local="clr-namespace:FirstModule.Views"
mc:Ignorable="d"
Height="450"
Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="Button"/>
</Grid>
</UserControl>
public partial class AView : UserControl
{
public AView()
{
InitializeComponent();
}
}
class AViewModel : IDialogAware
{
public AViewModel()
{
}
public string Title { get; }
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
}
public void OnDialogOpened(IDialogParameters parameters)
{
}
}
Then register the dialog and use the IDialogService instead of IDialogWindow.
public class TestModule : IModule
{
IDialogService _dialogService;
public TestModule(IContainerProvider containerProvider, IDialogService dialogService)
{
_dialogService = dialogService;
}
public void OnInitialized(IContainerProvider containerProvider)
{
dialogService.Show(nameof(AView), new DialogParameters(), result => {});
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<AView>();
}
}
This will show your view in the default dialog window, but as stated above, you can always roll your own, if you need to. For more information, see the dialog service documentation.

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

How to bind to a property of a class instantiated in the current class

I have two clasess, MainWindow and MainWindow_ViewModel.
MainWindow is defined like so:
public partial class MainWindow : Window
{
static public MainWindow wn;
public MainWindow_ViewModel mwvm;
public MainWindow()
{
InitializeComponent();
wn = this;
mwvm = new MainWindow_ViewModel();
}
}
MainWindow_ViewModel is defined like this:
class MainWindow_ViewModel
{
private List<String> _filtros;
public List<String> filtros
{
get
{
return _filtros;
}
}
public MainWindow_ViewModel()
{
_filtros = new List<String>();
_filtros.add("Filtro1");
_filtros.add("Filtro2");
_filtros.add("Filtro3");
}
}
Notice that there is no static methods or properties whatsoever.
In MainWindow's XAML I have a ListBox that I want to bind with the mwvm.filtros which should be available directly from code-behind.
How can I achieve that WITHOUT using DataContext and only in XAML?
Could it be possible to bind from another class (i.e. another window) to the following path? MainWindow.wn.mwvm.filtros.
Yes, of course. You don't need C# code to bind the view model. Just create an object in the DataContext element:
<Window.DataContext>
<local:MainWindow_ViewModel />
</Window.DataContext>
You have to create a namespace for your local project though. Full code:
<Window x:Class="Your.Namespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Your.Namespace"
>
<Window.DataContext>
<local:MainWindow_ViewModel />
</Window.DataContext>
You can't bind from another Window or Control unless you pass it along or make it static. If it is sub control of this Window, you can set its data context.

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

Get collection from subusercontrol in WPF

I have
<Window x:Class="Repo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Repo="clr-namespace:Repo" Title="Window1" Height="300" Width="300">
<Grid>
<Button Click="SaVeEverythingInDatabase></Button>
<Repo:UserControlTasks/>
</Grid>
</Window>
public class UserControlTasks:userControl
public partial class UserControlTasks: UserControl
{
public UserControlTasks()
{
InitializeComponent();
LoadView();
}
private void LoadView()
{
this.lbTasks.ItemsSource = new TaskModelView();//collectionOfTasks
}
How to get collection from lbTasks in UserControlTasks when I click button on MainWindow?
I must add that I this collection is a part of instances of class Student which is datacontext of MainWindow.
Create TaskModelView in MainWindow class and assign it to Button control and UserControlTasks control. You will need to add a dependecy property for this to UserControlTasks.

Categories

Resources