How to create a UserControl based on another UserControl? - c#

I created a UserControl called fooControl.
I would like to create another UserControl called fooControlExtended to reuse/add/override both the C# and XAML code that already exists in the base UserControl fooControl.

You can do it this way:
TestUserControl.xaml
<UserControl
x:Class="UserControls.TestUserControl"
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="using:UserControls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal">
<Button
Click="Button_Click"
Content="Click" />
<TextBlock
x:Name="TextControl"
Text="TestUserControl" />
</StackPanel>
</UserControl>
TestUserControl.xaml.cs
using Microsoft.UI.Xaml.Controls;
namespace UserControls;
// You need to remove the "sealed" modifier to allow inheritance.
public /*sealed*/ partial class TestUserControl : UserControl
{
public TestUserControl()
{
this.InitializeComponent();
}
protected void UpdateText(string text)
{
this.TextControl.Text = text;
}
protected virtual void OnButtonClick()
{
UpdateText("TestUserControl clicked");
}
private void Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
OnButtonClick();
}
}
TestUserControlEx.cs
namespace UserControls;
public class TestUserControlEx : TestUserControl
{
protected override void OnButtonClick()
{
this.UpdateText("TestUserControlEx clicked.");
}
}

Related

How to bind a method for custom dependency property via user control?

I currently have a Button inside my custom UserControl that needs to have a method name binded to it's Click dependency, the method name being provided from a custom dependency property in the user control. Any ideas on how to do this?
Page.xaml
<local:CustomButton OnClick="CustomButton1_Click" ... />
Page.xaml.cs
private void CustomButton1_Click(object sender, RoutedEventArgs e)
{
// do something...
}
CustomButton.xaml
<Button Click={x:Bind OnClick} ... />
CustomButton.xaml.cs
public sealed partial class CustomButton : UserControl
{
...
public static readonly DependencyProperty OnClickProperty = DependencyProperty.Register("OnClick", typeof(string), typeof(CustomButton), new PropertyMetadata(true));
public bool IsNavigator
{
get => (string)GetValue(OnClickProperty);
set => SetValue(OnClickProperty, value);
}
}
Do you mean you want to call CustomButton1_Click when CustomButton is clicked?
CustomButton.xaml
<UserControl
x:Class="UserControls.CustomButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UserControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Button Content="Button" Click="Button_Click"/>
</Grid>
</UserControl>
CustomButton.xaml.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
namespace UserControls;
public sealed partial class CustomButton : UserControl
{
public CustomButton()
{
this.InitializeComponent();
}
public event EventHandler? OnClick;
private void Button_Click(object sender, RoutedEventArgs e)
{
OnClick?.Invoke(this, EventArgs.Empty);
}
}
And use it like this:
<Grid>
<local:CustomButton OnClick="CustomButton_OnClick" />
</Grid>

Redirect to another page in WPF on certain conditions

Hi i am making a WPF application.
I have a mainwindow, which i have my navigation in, then i also have a stackpanel, with this:
<Frame x:Name="_mainFrame" NavigationUIVisibility="Hidden"/>
inside, where i place my pages inside.
In My mainwindow i navigate to other pages using the following to for example move to the gameWindow:
private void NavigateGameWindow(object sender, RoutedEventArgs e)
{
_mainFrame.Navigate(new GameWindow());
}
This works fine, but now that i am inside that window (gameWindow), i am checking if a "player" is set, if not, i want to navigate to another page, where i can set certain values.
and then navigate back to GameWindow.
But how do i get a hold of _mainFrame, when it is a part of the mainwindow ?
It says in GameWindow on _mainFrame
The name _mainFrame, does not exist in the current context
Game Window
public partial class GameWindow
{
private int numberOfPlayers;
private Player[] players;
private INavigator _navigator;
public GameWindow(INavigator navigator)
{
_navigator = navigator; //assign navigator so i can navigate _mainframe to other pages.
// initialize game properties, check if they are set.
var gameProp = new GameProperties();
this.numberOfPlayers = 2;
this.players = gameProp.CheckPlayerIsSet(this.players);
//check if a player has been set
if (this.players != null)
{ // Player is set or has been set. proceed or start the game.
InitializeComponent();
}
else
{ // redirect to settings window because players has not been set!
_navigator.Navigate(new GameSettings());
}
}
}
Main Window
public partial class MainWindow : Window, INavigator
{
public MainWindow()
{
InitializeComponent();
}
private void ExitGame(object sender, RoutedEventArgs e)
{
System.Windows.Application.Current.Shutdown();
}
public void Navigate(Page p)
{
_mainFrame.Navigate(p);
}
private void NavigateRulesWindow(object sender, RoutedEventArgs e)
{
Navigate(new GameRulesWindow());
}
private void NavigateGameWindow(object sender, RoutedEventArgs e)
{
Navigate(new GameWindow(this));
}
}
GameSettings
public partial class GameSettings : Page
{
public GameSettings()
{
InitializeComponent();
//var gameProps = new GameProperties();
// set number of players,, should prompt user, and get value!
//gameProps.SetNumberOfPlayers(2);
}
}
View for gamesettings
<Page x:Class="ITD.OOP_Projekt.WPF.Menu.GameSettings"
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:ITD.OOP_Projekt.WPF.Menu"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="GameSettings">
<Grid Background="white">
<TextBox HorizontalAlignment="Left" Height="23" Margin="229,144,0,0" TextWrapping="Wrap" Text="This is game settings" VerticalAlignment="Top" Width="120"/>
</Grid>
</Page>
One very easy solution is this:
So with the following code you have only one Window (Mainwindow) and inside that Window you display your pages. You can compare it with your internet browser. You have one window and inside that window you can navigate between pages (settings, game, highscore, ...).
I hope this helps and you can get it to work!
If not i can try to upload a simple example to github in the evening.
Just get rid of your GameWindow and implement it as a page.
MainWindow
xaml:
<Window x:Class="PageSwitcher.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:PageSwitcher"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Frame x:Name="MainFrame" NavigationUIVisibility="Hidden" />
</Grid>
cs:
public partial class MainWindow : INavigator
{
public MainWindow()
{
InitializeComponent();
Navigate( new Page1(this) );
}
public void Navigate( Page p )
{
MainFrame.Navigate( p );
}
}
Page1
xaml:
<Page x:Class="PageSwitcher.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:PageSwitcher"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="Page1">
<Grid Background="Green">
<Button Width="150" Height="30" Click="ButtonBase_OnClick" Content="Go to Page2" />
</Grid>
cs:
public partial class Page1 : Page
{
private INavigator _navigator;
public Page1(INavigator navigator)
{
_navigator = navigator;
InitializeComponent();
}
private void ButtonBase_OnClick( object sender, RoutedEventArgs e )
{
_navigator.Navigate(new Page2(_navigator));
}
}
Page2
xaml:
<Page x:Class="PageSwitcher.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:PageSwitcher"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="Page2">
<Grid Background="Blue">
<Button Width="150" Height="30" Click="ButtonBase_OnClick" Content="Go to Page1"/>
</Grid>
cs:
public partial class Page2 : Page
{
private INavigator _navigator;
public Page2(INavigator navigator)
{
_navigator = navigator;
InitializeComponent();
}
private void ButtonBase_OnClick( object sender, RoutedEventArgs e )
{
_navigator.Navigate(new Page1(_navigator ));
}
}
Thats all you really need.
In this example you can switch between two pages on button click events.
Just start a new wpf project and copy the code.
Play around with it until you understand it and then try to implement it in your game :)
If you want to redirect the page from one page to another you can create one method or function in which you can write the conditions and use the below code for redirection. It will take care of the directory also.
NavigationService.Navigate(new Settings.LatestActiveUsers());

Wpf Usercontrol, Check if RoutedEvent is bound

I have the following UserControl:
<UserControl x:Class="DueVCheck.Pl.Gui.CustomControl.ListInfoBar"
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:DueVCheck.Pl.Gui.CustomControl"
mc:Ignorable="d" d:DataContext="{d:DesignInstance local:ListInfoBar}" >
<Button Name="NewRowBtn" Margin="5" Click="NewRowBtn_OnClick" Content="New"/>
</UserControl>
The Code-Behind file:
using System.Windows;
namespace DueVCheck.Pl.Gui.CustomControl
{
public partial class ListInfoBar
{
public ListInfoBar()
{
DataContext = this;
InitializeComponent();
}
public static readonly RoutedEvent NewClickEvent =
EventManager.RegisterRoutedEvent("NewClick", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(ListInfoBar));
public event RoutedEventHandler NewClick
{
add { AddHandler(NewClickEvent, value); }
remove { RemoveHandler(NewClickEvent, value); }
}
private void NewRowBtn_OnClick(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(NewClickEvent)); }
}
}
}
Usage of the Usercontrol:
<customControl:ListInfoBar Margin="10,0,10,0" NewClick="NewRowOnClick"/>
What i need is that the Usercontrol disables the NewRowBtn whenever the NewClick is not bound via XAML. The Problem is that Add or Remove get never called when binding the Event over XAML.
How to fix this?

wpf Usercontrol in usercontrol no response

I have a strange problem in my project. There are pages made from usercontrol and menu bar (also usercontrol).
Here is my usercontrol that contains few buttons
public partial class UpperBar : UserControl
{
public UpperBar()
{
InitializeComponent();
}
public event EventHandler EventbtClicked;
private void btConnect_Click(object sender, System.Windows.RoutedEventArgs e)
{
EventbtClicked(this, e);
}
}
I added this in my page as follows:
<local:UpperBar VerticalAlignment="Top" Grid.Row="0" Height="78" Grid.ColumnSpan="3" Margin="0,2,0,0"/>
And in my page tried to call event:
public PageStatus()
{
InitializeComponent();
Plc.ExecuteRefresh += new EventHandler(RefreshLeds);
UpperBar.EventbtCliced += new EventHandler(UpperBatButtonClick);
}
protected void UpperBarButtonClick(object sender, EventArgs e)
{
//do something
}
But I can't access my event using this UpperBar.EventbtCliced, why ?
You need to access the instance of your class UpperBar in PageStatus, not the class UpperBar itself!
The easiest way for you here:
Name your UpperBar in your XAML, example:
<local:UpperBar x:Name="_myBar" x:FieldModifier="private"/>
Then use this instance in your PageStatus.xaml.cs:
public partial class MainWindow : Window {
public MainWindow()
{
InitializeComponent();
_myBar.EventbtClicked += new EventHandler(UpperBarButtonClick);
}
protected void UpperBarButtonClick(object sender, EventArgs e)
{
//do something
}
}
Now if you are working seriously in WPF, you should really learn about Databinding and MVVM, catching event this way is not the best way to do it at all.
You should use Custom Command (RoutedUICommand) rather than bubbling event from user control.
here are some steps to follow in contrast to your approach:
1: create class myCustomCommand.
namespace WpfApplication1
{
public class myCustomCommand.
{
private static RoutedUICommand _luanchcommand;//mvvm
static myCustomCommand.()
{
System.Windows.MessageBox.Show("from contructor"); // static consructor is called when static memeber is first accessed(non intanciated object)
InputGestureCollection gesturecollection = new InputGestureCollection();
gesturecollection.Add(new KeyGesture(Key.L,ModifierKeys.Control));//ctrl+L
_luanchcommand =new RoutedUICommand("Launch","Launch",typeof(myCustomCommand.),gesturecollection);
}
public static RoutedUICommand Launch
{
get
{
return _luanchcommand;
}
}
}
}
In the xaml of UserControl:
<UserControl x:Class="WpfApplication1.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:CustomCommands="clr-namespace:WpfApplication1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.CommandBindings>
<CommandBinding Command="CustomCommands:myCustomCommand.Launch" Executed="CommandBinding_Executed">
</CommandBinding>
</UserControl.CommandBindings>
<Grid >
<TextBox Name="mytxt" Height="30" Width="60" Margin="50,50,50,50" ></TextBox>
<Button Name="b" Height="30" Width="60" Margin="109,152,109,78" Command="CustomCommands:ZenabUICommand.Launch"></Button>
</Grid>
Now in User control code
Handle command_executed
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
mytxt.Text = "invoked on custom command";
}
}
}

How can I make the code-behind of UserControls inherit a base class?

I've got a page manager that keeps a collection of pages (usercontrols), sends itself to each page which can thus call its SwitchPage method at anytime enabling me to put in links from one page to another. This works well and allows me to have a quick menu etc.
public partial class PageManager : UserControl
{
private Dictionary<string, UserControl> Pages = new Dictionary<string, UserControl>();
private string defaultPageIdCode = "page1";
private UserControl currentPage;
private string currentPageIdCode;
public PageManager()
{
InitializeComponent();
LoadPages();
SwitchPage(defaultPageIdCode);
}
private void LoadPages()
{
Pages.Add("page1", new Page1(this));
Pages.Add("page2", new Page2(this));
}
public void SwitchPage(string pageIdCode)
{
currentPageIdCode = pageIdCode;
currentPage = Pages[pageIdCode];
PageArea.Content = currentPage;
}
}
However, each page (UserControl) has repeated functionality in it, e.g. saving the PageManager object internally, which I would like to put in a base class:
Page1.xaml:
<UserControl x:Class="TestPageManager23434.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="White"
Width="400"
Height="400"
>
<TextBlock Text="this is page1"/>
<Button Content="go to page 2" Click="Button_Click"
HorizontalAlignment="Left"
Width="200"
Height="30"
/>
</StackPanel>
</UserControl>
Page1.xaml.cs:
public partial class Page1 : UserControl
{
private PageManager pageManager;
public Page1(PageManager pageManager)
{
this.pageManager = pageManager;
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
pageManager.SwitchPage("page2");
}
}
Page2.xaml:
<UserControl x:Class="TestPageManager23434.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Background="White"
Width="400"
Height="400"
>
<TextBlock Text="this is page2"/>
<Button Content="go back to page 1" Click="Button_Click"
HorizontalAlignment="Left"
Width="250"
Height="30"
/>
</StackPanel>
</UserControl>
Page2.xaml.cs:
public partial class Page2 : UserControl
{
private PageManager pageManager;
public Page1(PageManager pageManager)
{
this.pageManager = pageManager;
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
pageManager.SwitchPage("page1");
}
}
How can make each UserControl inherit a base class? It doesn't work since each UserControl has XAML which can't be inherited. And if I try to inherit from a plain class that inherits UserControl then it tells me:
Partial declarations of
'TestPageManager23434.Page2' must not
specify different base classes
Instead of declaring the root element as UserControl, declare it as your derived class. You will need to specify the namespace as well e.g.
<local:PageBase x:Class="TestPageManager23434.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestPageManager23434">
</local:PageBase>

Categories