Help me to find a better programming approach - c#

My application has a set of base classes derived from almost all the UI controls
XCombobox,XButton,XMenu etc. All these classes have some additional functionality apart from standard functionality (ex: Serialization capability)
I use all these controls in my test windows application.
I want to implement a concept similar to themes in my application.
Ex: Say if i need a blue background
I have a public property exposed in all controls which sets my controls
(i.e XButton and XMenu) backcolor to blue
I feel this approach is lame. Tomorrow if my manager wants some other styling.
I will have to go to every control and change the backcolor one by one ...not that i mind ;)....but this never makes me a good programmer.
Time for some application of a design pattern (strategy pattern shall i say ?)
Is there a possibility wherein i can just change in one central place and the property shall get applied to all of my UI controls ?
If yes... Please help me in realising the same.
If not ... Suggestions for some more better ideas are welcome.

Define a class that has properties for the colors (you can also add in properties for logos etc).
Then either have your constants in the code of that class, or read them in from some XML.

You answered your question already.
Define constants for styling in central properties, and use these styling constants in your UI components :).

I would use a dependency injection container such as Unity for this, it will allow you to register you theme in a single location and have all of your controls resolve the theme whenever they need it.
For example, implement a simple interface which has the properties of the theme that each control will use.
interface IXTheme {
Color BackColor { get; }
}
Wherever your control needs to fetch this, such as in OnPaintBackground, you make a simple call to fetch the color, using the CommonServiceLocator (This comes packaged with Unity already.)
protected override void OnPaintBackground(PaintEventArgs pevent)
{
Color backColor = ServiceLocator.Current.GetInstance<IXTheme>().BackColor;
///...
}
Now, you can create you theme somewhere else based on that interface.
class XBlueTheme : IXTheme {
Color IXTheme.BackColor { get { return Color.Blue; } }
}
You then register the theme with the container and use the container to resolve your form.
IUnityContainer container = new UnityContainer()
.RegisterType<IXTheme, XBlueTheme>();
IServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
XForm myForm = container.Resolve<XForm>();

From what you're saying, it seems like if you just want to change the color, the easiest thing would just be to save the color in a variable somewhere, or have some kind of initialization function that every component calls where you can specify shared things like the color.
Also, since you mentioned that you're adding additional functionality to components, you may want to use a Decorator design pattern for that purpose.

You can make something like .skin file provided in .net web projects. Or just an xml file will do; For instance,
Make a .skin file and add your controls and styling definitions there.
Add the .skin file path in some public property of your control's base class.
Add an event OnDraw, the all the controls override and color itself with the color defined in .skin.
Better try utilizing the existing .skin file; though I am not sure how would you plan to parse the .skin file.
<TextBox BackColor="Red" ForeColor="Blue"/>
<Button BackColor="White" ForeColor="Green"/>
<DropDownList BackColor="Cyan" ForeColor="Pink"/>
You can even extend the skin file by adding the cssClass property; and add styling according to css class defined in the css file.
<TextBox cssClass="TextLoginField"/>
<DropDownList cssClass="ComboLongList" />
Just thinking out loud! Btw, this article might give you an insight.

I guess the strategy pattern that you've mention fits the best.
That book Head Fisrt Design patterns describes this issue very well.
you need an interface say IStyle defined as a member of your base class so that the style behavior will be independent of your control inheritance.

Related

Is there any unique identifier for wpf UIElement?

For logging user actions in my WPF forms, I added some global event handlers
I want to log exactly which control fire the event, is there some unique identifier for a wpf UIElement like ClientId in ASP.Net?
Why don't you use the Hash Code.
You can compare the values to make sure they are the same object, and its easy to get them with .GetHashCode()
Edit
Obviously this is different every time you run the program, so actually this is prolly a bad idea, unless you want to update the log each time the process is logged. Still possible though
I mean you could store a hash value for each object at the time the log is created, but i don't know if I like that
Seems I found answer to my question, the answer is No, now way to do that, As noted in MSDN here (http://msdn.microsoft.com/en-us/magazine/dd483216.aspx)
Notice that the top-level Window control definition does not contain a
Name attribute. This is significant because, as we'll see shortly,
when you write test automation, an easy way to get a reference to a
control using the MUIA library is to access the AutomationId property,
which is generated by the compiler from the control's Name attribute.
Controls without a XAML Name attribute will not receive an
AutomationId property. This idea is a specific, low-level example of
the importance of considering application design issues for things
such as security, extensibility, and test automation.
One way you can do this is with a custom attribute. Like so...
The UIElement you want to log (UserControl for example):
[UserInterfaceID(ID = "{F436E9B3-C2F6-4CF8-8C75-0A2A756F1C74}")]
public partial class MyUserControl : UserControl
{
InitializeComponent();
// or whatever...
}
Then you need the custom attribute class
[System.AttributeUsage(AttributeTargets.Class)]
public class UserInterfaceIDAttribute : Attribute
{
public Guid ID { get; set; }
}
Now in your code, you can do something like this:
MyUserControl control = new MyUserControl();
foreach(object att in control.GetCustomAttributes(typeof(UserInterfaceAttribute),false))
{
UserInterfaceAttribute uiAtt = (UserInterfaceAttribute)att;
Guid theID = uiAtt.ID;
}
Because you are tagging the control with an attribute in the code, the unique identifier never changes no matter how many times you kill / launch the application.
Of course this is a basic example that shows how to access the ID but you will probably want to use some type of Aspect Oriented Programming. I do exactly this kind of thing using Castle Windsor Interceptors, but that is out of the scope of this post.
Ideally, you will be accessing this ID when there is some kind of event that gets fired. Using interceptors allows you go capture method calls before they are invoked wherein you can look up the ID as shown above and log the action. Alternatively, you can just use
this.GetCustomAttributes(...)
in some method when an event is fired on the control and embed your Logging code there. This pattern is not the best because you're sprinkling cross-cutting concerns all over making some type of Aspect Oriented Programming approach better...but again I digress and it is out of the scope of this post...but you get the idea.
Hope this helps.
You're just looking at adding a Name or x:Name so that the Window/UserControl/Page exposes the control to the rest of the class with the specified name.
<Window ...>
<Grid>
...
<!-- These controls are named, so you can access them directly by name -->
<Button x:Name="btnMyNamedButton" ... />
<Button Name="btnMyOtherNamedButton" ... />
<!-- This control is not named, so you can not directly access it by name -->
<Button ... />
<Grid>
</Window>
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
//btnMyNamedButton can be accessed
//btnMyOtherNamedbutton can also be accessed
//The third button can be accessed, but not directly by name.
}
}
Also, you can always use the FrameworkElement.Tag object. It's meant to store arbitrary information, so you can use this as a unique identifier if you want to.
I believe, for logging user actions, you can use the UIAutomation tree and the AutomationElement.AutomationId property, because this approach is supported in all standard UI controls by default. Many third-party controls are also supports the AutomationId for their elements (e.g. grid cells). An AutomationId is useful for creating test automation scripts.
see FrameworkElement.Tag Property
The Tag property can be used. It is of type object and can be set to anything.
I think UIElement.Uid should work. Assign it in XAML and access it in code.
<Label Uid="FirstName"/>
OR in a style property
<Setter Property="Uid" Value="SecondName"/>
Then refer in C# code:
if (Keyboard.FocusedElement is UIElement uiElement)
{
Debug.WriteLine(this, $"{uiElement.Uid}");
}

Access Pivot Control from App.xaml.cs

In my MainPage.xaml, I created a Pivot Control: <controls:Pivot Title="Powder God" Name="PivotControl">.
My first pivot view is a HubTile that summarize all other individual pages. So my application bar will be different between the first pivot view and all other ones.
That's why I put my application bar in App.xaml's resource section, then load based on selected index of my pivot.
My question is:
In the application bar I will be using for all individual pages, I want to have a delete option, where I will remove that specific item (a view model) from my data context.
I know I can use PhoneApplicationFrame root = Application.Current.RootVisual as PhoneApplicationFrame; to access navigation services, but I don't know how can I reference to my pivot, so that I can get the selected index and proceed forward.
Thanks!
Using MVVM you SHOULDN'T do this:
((PageType)Application.Current.RootVisual).PivotControl. //Blah
PageType is whatever type PhoneApplicationFrame is that contains your PivotControl. If this doesn't work you need a Property in the RootVisual
PAGE
public Pivot MyPivot
{
get
{
return PivotControl;
}
}
APP
((PageType)RootVisual).MyPivot. //Blah
On one level Microsoft's suggestion of putting the ApplicationBar in App.xaml is great as it can be referenced from everywhere and would appear to encourage code reuse: however this question highlights the limit to this approach. An application bar is typically used to provide actions which are specific to the current page (or pivot item) and just because the buttons are the same you may not want the exact same code to run in each case.
In this case I think it would better to create a factory method that creates your common ApplicationBar with the click handlers you specify specific to your page/pivot item. For bonus points put the method in a new class (not App) so it doesn't get lost in all the boilerplate code there. Call this factory method in your page constructor and remember your ApplicationBar in your class. For multiple app bars, create them all up front and you can then easily switch between these app bars in your Pivot SelectionChanged code.
The alternative of creating the ApplicationBar in App.xaml and then retrieving this from the App.xaml.cs "Resources" ResourceDictionary in code, modifying the click callbacks, is more complicated in my opinion.
I wish they'd done a better job of implementing the ApplicationBar so people wouldn't want to do this. I've found that using the ApplicationBar forces you to add code to your Page.xaml.cs even if you use a framework like MVVM Light. This is still OK in MVVM as it's UI specific code that belongs in the View, but it makes things inconsistent if you're using ICommand everywhere else. Last time I decided it was better to create the entire ApplicationBar in code rather than hack this kind of thing via App.xaml.cs.
Update: There is a UserVoice request for a data bindable ApplicationBar.

How can I easily keep consistent UI settings in C# Winform application?

I have a lot of different UserControls and would like to maintain consistent UI settings (mainly colors and fonts). My first try was this:
public class UISettings
{
//...
public void SetupUserControl(ref UserControl ctrl)
{
ctrl.BackColor = this.BackColor;
}
}
to be called in every control like this:
settings.SetupUserControl(ref this);
As this is read-only it cannot be passed by ref argument so this does not work. What are other options to keep consistent UI without manually changing properties for every item?
Inheritance! If you have a form or control that will constantly be using the same styles and you want to set that as your base, just create your own user controls that inherit from a form/control. By default all of your forms will inherit from "Form". Instead of inheriting from the default form, create a new user control that inherits from Form, and then have that as your base class.
CustomForm : Form // Your custom form.
Form1 : CustomForm // Inherit from it.
...the same works for components. If you want a button to have the same styles across the board, create a user control and have it inherit from the button control -- then use the custom control.
Whenever you want to make a change to your base styles, or any settings, simply change your custom controls settings -- your new forms/controls will automatically be updated!
Do the same thing. Don't pass it by ref. UserControl is a reference object already, so there's no need to pass it into your method using the ref keyword.
You may also want to consider a recursive method that will find all the UserControls on the form and pass it into your method.
How about a base class which provides such settings?
Two answers:
You don't need ref, controls are objects are reference types. Just drop it.
Create a Base UserControl and derive your controls form that base. You can still do that, just edit the class definitions of the controls. For new controls you can follow the Wizard.
A tip: setup the styling in the baseControl. Then make sure the derived controls don't override, the best way to do that is scanning the *.Designer.cs files and remove all settings that you know should come from the base.

Customizing the BulletChrome element in WPF

I'm trying to customize the look of a checkbox in WPF. I was hoping I could grab the default control template for the BulletChrome class that's defined in PresentationFramework.Aero and work with that. However, BulletChrome is not a sublcass of Control, so there's no template to modify. Does anyone know I could do this?
If you want to place some sort of BulletChrome in CheckBox' Template where the BulletDecorator in the classic Template would go, you could do that, since BulletChrome inherits from Decorator, which inherits from FrameworkElement.
The next part, how does the BulletChrome get its looks? Well, this is one of the rare parts from WPF where they handle rendering completely without xaml: The ButtonChrome's visual appearance is defined in its OnRender() method.
BulletChrome.OnRender(), from Reflector:
protected override void OnRender(DrawingContext drawingContext)
{
Rect bounds = new Rect(0.0, 0.0, base.ActualWidth, base.ActualHeight);
this.DrawBackground(drawingContext, ref bounds);
this.DrawDropShadows(drawingContext, ref bounds);
this.DrawBorder(drawingContext, ref bounds);
this.DrawInnerBorder(drawingContext, ref bounds);
}
Unfortunately, since all these methods called inside OnRender() are private, you can't mess with them even if you subclass the ButtonChrome, perhaps only overlay some of your rendering on top.
So basically, you either start digging through rendering code in Reflector and try to adapt and rewrite it to your needs, or roll your own Template/Decorator/whatever from scratch. (But then it really isn't important what you use as long as it works, right?)
Hope this answered your question, cheers.
You don't want to do this. Changing the control template is not supposed to change the behavior of the control, and a CheckBox control, by definition has three states (Checked, Unchecked, Indeterminate).
You're better off creating a custom 4-state (or n-state if you prefer) Control that borrows alot of Look/Feel from the CheckBox ControlTemplate.
If BulletChrome is not customisable, you can't customise it. But you definitely can replace it with something that is customisable.
In practical terms I would suggest starting with Silverlight's theme instead of Aero.

Should I Refactor This Code?

I am working on modifying a control on a existing site. All controls from the site inherit form a base class. I have a requirement to hide several links on the master page so I wrote this method on my control:
private void HideCartLink (bool visible)
{
Control control1 = Page.Master.FindControl( "link1" );
control1.Visible = visible;
Control control2 = Page.Master.FindControl( "link2" );
control2.Visible = visible;
}
I then moved on to another control and I had to do the same thing. So I refactored my code and modified my base class with this:
public void HideMasterPageControl (string controlName, bool visible)
{
Control control = Page.Master.FindControl( controlName );
control.Visible = visible;
}
and added this method on my controls:
void CartLinkVisible(bool visible)
{
////hide cart link
HideMasterPageControl("link1", visible);
HideMasterPageControl("link2", visible);
}
Now I moved on to a third control and realized I have to do the same thing.
Should I refactor my code one more time so that my base class has a method that knows specifically which links to hide? Or should I leave my base class generic and let my controls decided what to hide?
I am not sure what the rule is here...
If I'm honest, I'd be more inclined to turn this upside-down. I'd have something that added the buttons/links as necessary, based on the criteria of the page. This would then give you something more like a toolbar, and in fact you could make it configurable (or based on user privileges) which buttons/links appear on each page.
This saves you from the awkward position of working out on what basis to hide things that may or may not even be there.
Of course, assuming you can't do this, you're probably making the best of a bad job to be honest. Don't worry too much further about the about the final implementation. With only a few controls you're okay and would be making it worse by over-complicating it.
You might want to consider the Visitor pattern, though. This would mean you implement a class that "visits" all the links on a given control and goes to configuration to look up whether they should be hidden or not. This would save you hardcoding the control names for the links, and allow the method to be in a base class that has no idea what actual controls there are.
I'd have a generic base method that would call a virtual method to get a list of links to hide and cycle through them. The base implementation of the second method would contain the list of most commonly hidden links. Each control I'd just overwrite the method to add or modify that list.
Though, I have to agree with Neil, it seems better if you flip the logic and decide which links need to be included vs. which need to be excluded.

Categories

Resources