Inheriting App.xaml.cs [duplicate] - c#

I am fairly new to WPF and I am having a problem with inheriting from a user control.
I created a User Control and now I need to inherit from that control and add some more functionality.
Has anyone does this sort of thing before? Any help would be greatly appreciated.
Thank you

Well .. you create your base control
public abstract class BaseUserControl : UserControl{...}
then in the XAML file :
<Controls:BaseUserControl x:Class="Termo.Win.Controls.ChildControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Namespace.Of.Your.BaseControl">
And that should work.
EDIT: Hmm.. this example is useful when you have a base control without XAML and then inherit from it. The other way around(from a base control with Xaml) - I'm not sure how you can go about it.
EDIT2: Apparently from this post + comments i take that what you want might not be possible.

AFAIK you cannot inherit the xaml, you can only inherit the code behind.
We recently encountered the same problem on our project. The way we ended up solving our problem was to create a usercontrol and adding it to the "child" usercontrol.
If that doesnt work/help take a look at this:
https://web.archive.org/web/20200815091447/http://geekswithblogs.net/lbugnion/archive/2007/03/02/107747.aspx[1]

I may have a bit of a solution: Composition instead of inheritance - I have come up with control, that has 'content slots' assignable from outside through databinding, look at my SO thread.
Example of use:
<UserControl ... >
<!-- My wrapping XAML -->
<Common:DialogControl>
<Common:DialogControl.Heading>
<!-- Slot for a string -->
</Common:DialogControl.Heading>
<Common:DialogControl.Control>
<!-- Concrete dialog's content goes here -->
</Common:DialogControl.Control>
<Common:DialogControl.Buttons>
<!-- Concrete dialog's buttons go here -->
</Common:DialogControl.Buttons>
</Common:DialogControl>
<!-- /My wrapping XAML -->
</UserControl>
Together with some handling code in codebehind it would be a nice base component for dialog windows.

You cannot inherit the xaml code it self. However creating an abstract class of the codebehind, will allow you to edit in code behind, from a derived class object.
Xaml Code: { Window1.xaml }
<Window
x:Class="WPFSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="auto" Width="256" Title="WPF Sameples">
<Grid>
<Button x:Name="Button1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Click Me"/>
</Grid>
</Window>
CodeBehind: { Window1.xaml.cs }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 WPFSamples
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public abstract partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
Derived Class : { DisabledButtonWindow.cs }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WPFSamples
{
public sealed class DisabledButtonWindow : Window1
{
public DisabledButtonWindow()
{
Button1.IsEnabled = false;
}
}
}
although you cannot inherit from the wpf source it self, you are able to use this "Window1" control as a template for all other derived controls.

You can accomplish this by using a delegate.
Essentially, you need to create an interface (YourInterface) which wraps up the functionality you want, then make both the user control and your class implement that interface.
Next, make sure the user control has a reference to an object of type IYourInterface, so that when your user control attempts to invoke a method of the Interface, it calls your class' method.
Because both the user control and class implement the same interface, they can be seen as the same kind of object - meaning you can put them both into a collection of objects of type IYourInterface. This should give you the behavior you want.
In ASP.NET I use this technique often, by having my classes inherit from abstract class ancestors. I don't understand why WPF doesn't support this. :(

I think that you can do this but that you will have to redefine any functions and possibly some other stuff that you reference in the xaml in the child class.
IE if you have a button click event that you subscribe to in the base class xaml you will need override the button click in the child class and call the base class button click event.
Not one hundred percent sure of the the details since it's my coworkers code that I'm drawing from but thought this would give a start to anyone looking to implement this in the future.

Related

List Box Controls in Visual Studio to Auto-scroll

I am working on a WPF main window and I am using a list box, and I want the list box to auto-scroll whenever new data is added. I used the ListBoxBehavior class in the chosen answer for this question, and I added the following namespaces for the that class in my code:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
Also, in my XAML, I added the following:
<ListBox x:Name="IncomingData" FontSize="20" Grid.Column="1" Margin="10,10,10,0" Grid.Row="3" ItemsSource="{Binding SourceCollection}" lb:ListBoxBehavior.ScrollOnNewItem="true"/>
However, I am getting the following three errors in my XAML code regarding that line, and they are as following:
Error XDG0006 The namespace prefix "lb" is not defined.
Error XDG0008 ListBoxBehavior is not supported in a Windows Presentation Foundation (WPF) project.
Error XLS0415 The attachable property 'ScrollOnNewItem' was not found in type 'ListBoxBehavior'.
I tried creating an object of a ListBox type ListBox lb = new ListBox(); in the ListBoxBehavior class, but that didn't change the situation. Also, ScrollOnNewItem already exists in the class, so why is it not identifying it?
Is there a missing step that I should have done?
Any help is much appreciated!
you need to define the lb namespace before using it.
at the top of your xaml file you ought to see xmlns:x="...". notice you are using it with x:Name.
same goes for lb. you need to define xmlns:lb="...". intellisense should help you fill in the "...".
notice xmlns means xml namespace.
that ought to clear up all 3 errors.

In WPF, access a control that is instantiated in a XAML file from a separate Class?

We have a class in our WPF project that we want to access a control that is put into a XAML file. I have put my code below and file structure to help with my question.
Folder Structure:
Navigation Directors\ FullKioskDirector.cs
MasterTemplates \ SellAllKioskMaster.xaml
Views \ Pages \ PageTemplates \ PageAttractScreen.xaml
We want 'FullKioskDirector.cs' to access the visibility of 'PageAttractScreen.xaml'. The 'SellAllKioskMaster.xaml' is referencing the 'PageAttractScreen.xaml' in its XAML.
Here is our code below.
SellAllKioskMaster.xaml
<UserControl
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:UserControls="clr-namespace:Kiosk.Views.Pages.UserControls" xmlns:PageTemplates="clr-namespace:Kiosk.Views.Pages.PageTemplates" x:Class="Kiosk.MasterTemplates.MyContainer"
mc:Ignorable="d"
d:DesignHeight="1049" d:DesignWidth="1912" Background="White">
<Grid>
<!--I need to access the visibility of these elements from the 'FullKioskDirector.cs'-->
<PageTemplates:PageAttractScreen x:Name="pageAttract" Margin="0,100"/>
<PageTemplates:PageWelcomeScreen x:Name="pageWelcome" Margin="0,100"/>
<PageTemplates:PageProductsScreen x:Name="pageProducts" Margin="0,100"/>
</Grid>
</UserControl>
FullKioskDirector.cs
using System;
using System.Windows;
using System.Windows.Controls;
using Kiosk.Common.Common.Contracts;
using Kiosk.Views.Pages.UserControls;
namespace Kiosk.Directors
{
public class FullKioskDirector : IPageNavigation
{
public FullKioskDirector()
{
/*
Want to control visibility of my controls that are placed and
x:Named in the SellAllKioskMaster.xaml
*/
}
How can I accomplish this?
It's better if you do it in an MVVM approach, rather than doing everything from code behind.
Nevertheless, wherever you are creating FullKioskDirector, just pass in pageAttract to the constructor.
Assuming you create the FullKioskDirector at UserControl's constructor
public UserControl()
{
var fullKioskDirector = new FullKioskDirector(pageAttract);
}
Then you can use it like this
public FullKioskDirector(PageAttractScreen pageAttract)
{
pageAttract.Visibility = Visibility.Collapsed;
}
I would use a Publish / Subscribe pattern.
Example: MessageBus / EventAggregator
This is my tool of choice when dealing with dependency challenges.
Essentially, you just post a message for subscribers to react to.
In this case your subscriber will then post a response in the form of a control.
You can leverage Bizmonger.Patterns to get the MessageBus.
https://msdn.microsoft.com/en-us/library/ff921122.aspx

Initializing XAML user control

I am very new to C# and I'm trying to initialize a XAML user control window when I start my scripting program. It's just a basic window with textboxes, and comboboxes. The XAML code and C# code are listed below respectively. Since I have Express, I am unable to use the MVVM light toolkit. I am also using VS2010 because that is what the original code for this program was. The VMS.TPS.Common.Model.API and Types are dll's used for this particular program. Keep in mind that the C# code has to have this basic skeleton, otherwise it won't work. The 'public void Execute' portion is where I need to code.
<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:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="426" d:DesignWidth="736">
<Grid Margin="10" Width="702" HorizontalAlignment="Center">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VMS.TPS.Common.Model.API;
using VMS.TPS.Common.Model.Types;
using System.Windows;
using System.Windows.Forms;
using WpfApplication1;
namespace VMS.TPS
{
public class Script
{
public Script()
{
}
public void Execute(ScriptContext context, System.Windows.Window window)
{
}
}
}
It should be very simple if i understood it right :
UserControl1 testUsrCtrl = new UserControl1();
And then set required properties.
Make sure you have all the references in place.

How to properly update settings from menus

If I have a user setting ToggleThis
I want to have this setting availabe to the user in a menu, say Settings/ToggleSettings. clicking it. Each click should toggle the user setting true/false but also update the menuItem icon to display the actual setting.
I can do this using
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Menu IsMainMenu="True">
<MenuItem Header="_Settings">
<MenuItem Header="_Toggle" Name="ToggleSettings" Click="MenuItem_Click">
<MenuItem.Icon>
<Image Source="Images/Toggle.png" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
if (ToggleSettings.Icon == null)
{
Uri Icon = new Uri("pack://application:,,,/Images/" + "Toggle.png");
ToggleSettings.Icon = new Image
{
Source = new BitmapImage(Icon)
};
Properties.Settings.Default.toggleThis = true;
}
else
{
ToggleSettings.Icon = null;
Properties.Settings.Default.toggleThis = false;
}
}
}
}
However, I know this isn't the correct way of doing it as for example, on launch the menu probably won't be in the correct state based on previous settings. Trouble is, I don't know the right way. Can anyone give me some pointers on the right way to do this?
I'm assuming I need to use binding on both the icon and/or some value in the MenuItem but don't really know where to start.
Thank you
Actually there is no "right" way, there is only what works best, and what is most appropriate given the context.
Your example looks fine, it seems, so far at least, the only issue you have, is that you will not have the selected option in sync with what the user chose/didn't choose, the last time they used the software.
This requires only two small pieces of your code to be in two particular places.
Austin pointed out one of them already: Save your settings. This you should do right after your if/else in your method: MenuItem_Click. Just make sure the method does not exit somehow before the call to Settings.Save is made... a try/catch with a graceful way of ensuring a consistent settings state would be prudent.
The other is at the "time" you yourself mentioned: Initialization, or startup of the app. Somewhere in your app, before the initial loading is completed, you must access the setting you created (toggleThis) and use it to set the initial state of your menu item.
The best way to facilitate this, is to have a private method, which is responsible for both changing what icon is showing on the menu item, as well as storing the most recent state in the settings of the app. A method called Toggle() perhaps, which you call within your MenuItem_Click method. You need to give the menu item in question and ID though, that can be used to access the menu item in your code-behind though. As well, this code example assumes you have your icons stored in settings as well, although the icons can be coming from wherever, as long as you can reference them.
So your code could be something like this, although not exactly this:
public MainWindow()
{
InitializeComponent();
this.SetToggleIcon(Properties.Settings.Default.toggleThis);
}
private void Toggle()
{
this.StoreToggleState(!Properties.Settings.Default.toggleThis);
this.SetToggleIcon(Properties.Settings.Default.toggleThis);
}
private void SetToggleIcon(bool state)
{
this.menuItem_ToggleSettings.Icon = (Properties.Settings.Default.toggleThis) ? Properties.Settings.Default.IconTrue : Properties.Settings.Default.IconFalse;
}
private void StoreToggleState(bool state)
{
Properties.Settings.Default.toggleThis = state;
Properties.Settings.Default.Save();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
this.Toggle();
}
You need to call Save when you deem it appropriate.
Properties.Settings.Default.Save();
It's not entirely clear how you're using it but this will ensure the updated value is at least stored.

Tricking a Usercontrol to allow "." namespaces

I have a 3rd party control (Visifire) which has a namespace that uses the "." format. This works fine in a WPF application, but not in a UserControl as it generates a "can't find assembly" if you try to include the namespace. This means I have to use code to add the control, set up the bindings, etc, etc, which is quite annoying as I would prefer to use XAML.
My thought was to trick the UserControl using the following:
namespace MyControl
{
public class MyChart : Visifire.Charts.Chart
{
public MyChart () : base() {}
}
public partial Chart : UserControl
{
// All the control stuff goes here
}
}
Then, in XAML, I would use:
xmlns:local="clr-namespace:MyControl"
<Grid>
<local:MyChart>
</local:MyChart>
</Grid>
This doesn't seem to work, as it generates an exception.
Anybody have any tips on how I could get around this? THanks much!
You can use:
<Grid xmlns:charts="clr-namespace:Visifire.Charts;assembly=Visifire">
<charts:Chart>...</charts:Chart>
</Grid>
To import a fully-qualified namespace, does that not work for you?

Categories

Resources