|
|
Rather than relying on the inbuilt formatter, which has a number of shortcomings with regards to internationalisation, I tend to use a custom value converter (partly because I deal with financial software a lot, where it's common to convert a negative number to sit inside brackets). This makes for a very flexible solution, and allows you to change the language format mid application with ease.
|
|
|
|
|
Do you mean like a converter class which has a method to accept the currency and return it with the £ infront of it?
|
|
|
|
|
Sort of, but it doesn't need to accept the currency - it converts to it internally, and it's capable of reacting to culture changes.
|
|
|
|
|
|
|
Hi everyone,
I'm very new to silverlight, and trying to build a custom control which is made up of a series of paths/shapes which are of varying sizes.
Is there some sort of container that exists which you can put a series of paths/shapes in, and when stretched it scales the whole lot like you'd scale a picture??
My problem is that whenever the control is resized, (e.g. while building main.xaml) my elements all scale by different amounts, because their margins are not scaled.
e.g. Say the control (200x100) consists of
A Grid (1x1) containing:
--A Large Rectangle 200 x 100 [size of entire control, margins 0]
--A Small Square 50x50 in the centre of the grid, [so margins are 75 L&R, 25 top&Bottom]
When the control is squashed to e.g. 100x50, the margins for the small square are bigger than the entire control (75L+75R = 150), so the square vanishes. Conversely, when the control is doubled in width to 400 pixels, the small square grows not by 2x, but by 5x (from 50pixels to 250 pixels), because the margins are still 150pixels total. I need these margins to scale, so when the control is half the size, so are the margins and visa versa.... Or at least something that emulates that.
I've tried trying to make the grid have a row/column for everything that needs laying out and using the 'star' system, but some of these controls will be made up of 20 or so different paths/shapes of different sizes and locations and it's beyond impractical to implement (also buggy :S ).
Surely there's some sort of container that exists which you can just put paths/shapes in, and when stretched it scales the whole lot like you'd scale a picture??
Help!
|
|
|
|
|
You might want to take a look into the viewbox. There's a really good demonstration here[^].
|
|
|
|
|
You are correct. The grid does not scale fixed margins, which makes complete sense. Using the star (*) ratios on columns and rows *does* work, but there are a few minor gotchas.
As Pete mentioned, the ViewBox will automatically scale when you resize the control, but sadly, you are going to find out that it doesn't really scale in the way that you would probably expect . The ViewBox scales *EVERYTHING*... elements, locations, fonts, etc. When you resize your control, do you really want your 1 pixel thick lines to suddenly become 5 pixels thick? If you do, then yeah, the ViewBox is the ticket. If you don't, then you need to use the Grid .
I've run into situations where I wanted to scale certain portions of the control only... take for example if you were drawing a bicycle wheel. Two circles plus a bunch of 1 pixel thick spokes for arguments sake. You'd probably want to scale the size of the two circles, but you probably would NOT want to scale the size of the spokes, you'd probably want to keep them 1 pixel thick.
If you use a ViewBox in that case, its a *MAJOR* PITA.
|
|
|
|
|
Thanks so much! I had thought of the viewbox earlier but it only accepts one item. Your reply helped me realise that that one item could, of course, be a 1x1 grid holding all of the elements...
Just for my learning's sake, if you did want to scale certain portions of the control only (e.g with your bike-wheel example) do you end up having to write your own container control?
|
|
|
|
|
First off, let me correct you on one thing that will open up your world ... there is no rule that says you can't have multiple containers in one window on top of each other. I.e. a window doesn't necessarily have to be:
<Window>
<ViewBox />
</Window>
it could also be:
<Window>
<Grid>
<ViewBox />
<Grid />
</Grid>
</Window>
Not saying the 2nd option is always a good idea because it could be very difficult if not impossible to sync up the two containers if they are different depending on your content.
Anyways, in regards to the bicycle wheel, I used that example because I actually had to do a control kind of similiar to that. I wanted to scale the size of the two circles and the *length* of the spokes, but I wanted the stroke thickness of the two circles and the spokes to remain consistent at one pixel.
I did in fact end up using a ViewBox for that, but to keep the lines a consistent stroke thickness, I defined a DependencyProperty of type double that was updated with the inverse scaling ratio as the control was resized and bound it to everything I wanted to keep consistent.
So the original stroke thickness was defined as 1.0, and if the user scaled to 2x the original size for example, the stroke thickness would be updated to 0.5 to keep the lines at 1 pixel thickness. If they scaled to 50%, the stroke thickness would be updated to 2.0.
You really have to play with your particular content to see how it scales in the ViewBox by default. Its sometimes kind of wacky and you have to do wacky stuff to compensate.
|
|
|
|
|
Fully understood. Thanks so much for your time - it's really helped! Uses for dependency properties seem to be a lot more obvious now too... Cheers!
|
|
|
|
|
Is it possible to derive a reusable class from System.Windows.Application? I want to make an "ApplicationEx" class with some extended functionality.
Problem is that App is derived from System.Windows.Application and its a partial class, so if I change App to derive from a class that derives from Application instead of deriving from Application directly, it doesn't jive with the App.g.cs code behind.
What I mean is:
public class ApplicationEx : ApplicationEx
{
}
public partial class App : ApplicationEx // instead of Application
{
}
I don't want to loose app.xaml functionality.
|
|
|
|
|
Never tried that, so not sure if another error will pop up, but you can get around that particular error easily.
The App.g.cs file is generated by the XAML compiler. If you check out the App.xaml file, you'll see it starts with:
<Application x:Class="..."
That "Application" tag is the one that has to change to ApplicationEx (With the appropriate namespace prefix), in order to make the App.g.cs match.
|
|
|
|
|
Lol, yeah, I'm a total idiot. I forgot about that part of the change. I was just about to delete the post when you posted .
|
|
|
|
|
|
Hmm... it didn't really work after all.
ApplicationEx lives in a seperate assembly. ApplicationEx has (or attempted to have the entry point in it):
public class ApplicationEx : Application
{
[STAThread]
public static void Main(string[] args)
{
}
}
So after fixing the mistake in app.xaml, it gets past that error, but it doesn't see the entry point in ApplicationEx.
I thought that would work
|
|
|
|
|
So make your own Main function that just creates an ApplicationEx and runs it. You can specify the entry point in a WPF app.
|
|
|
|
|
Yeah, I was trying to encapsulate "everything", but I guess there is no way around having a static Main() in the exe itself.
|
|
|
|
|
Heh, well encapsulating Main() might be a little overboard... I mean, you can always have your ApplicationEx do its initialization in the constructor, or even do a factory-style constructor instead to preserve command-line args (If you need them)...
Application app = ApplicationEx.Create(string[] args);
|
|
|
|
|
Yeah, I ended up having an ApplicationEx.StartupEx method (lol, you can totally tell I come from the MFC / Win32 world with all the "Ex" names) that takes the type for the user application class along with the args and then it creates the application and/or manages the single instance stuff. It does require the user to stub out a Main() and forward the call to my DLL though. I was trying to avoid that. Oh well.
Now I'm just having a bit of trouble figuring out a common place to process the command line for the first and subsequent instances since some of the WPF start up code is syncronous (Application.Run()). I've got it working for the second instance though. It does forward the args to the first instance.
I'm using the WindowsFormsApplicationBase technique to do the singleton app stuff. It does have the different entry points for the first / subsequent start ups (OnStartup / OnStartupNextInstance).
2nd+ instance is going through OnStartupNextInstance and calling a virtual method in ApplicationEx, but 1st instance is a bit trickier since I haven't quite convinced myself if that case should be passed in before the main window is created, but I'm thinking it probably should.
Its weird though... popping up a message box before the main window is created somehow creates the main window...
|
|
|
|
|
Heh, you're losing me here... Not sure exactly what you're trying to do, and I'd never even heard of WindowsFormsApplicationBase until now... Are you starting up multiple GUI threads? Usually don't want to do that in a WPF app, unless you have a really good reason for it.
But anyway...
Yeah, Application.Run() is synchronous. I generally handle command line apps by making a "Globals" static class to hold that and a few other properties... The kind of things that get set once on startup and then never ever ever ever EVER modified... Stuff like command line arguments, modes to turn off non-developer features or prevent external writes during testing... Just don't use something like that for read/write storage, or you'll just create all sorts of design issues.
|
|
|
|
|
I'm making an "ApplicationEx" class that encapsulates single application instance functionality and the WindowsFormsApplicationBase technique is one of the more popular ways to do that. No multi-threaded GUI threads . WindowsFormsApplicationBase is just MSFT's wrapper for that stuff and they do all the inter-process communication like forwarding the new cmd line args to the previous instance.
Think about IE... if you type "start http://www.microsoft.com" at the cmd prompt, it starts up IE and goes to www.microsoft.com. Now if you type "start http://www.cnn.com", it keeps the same one instance of IE, but opens up a 2nd tab to www.cnn.com. Obviously a 2nd instance of IE ran and exited and somehow forwarded the args to the first process.
WindowsFormsApplicationBase provides a pretty clean mechanism to get the SECOND instance cmd line args to the singleton instance, but it doesn't provide a very clean way to get the original instance cmd line args out of the static classes.
I think I'm kind of going to do what you suggested and add a "LastCmdLineArgs" property to ApplicationEx. Kind of weird that Application doesn't have that already.
|
|
|
|
|
Ah, gotcha... I do that with a lightweight launcher EXE that sends args over a named pipe.
|
|
|
|
|
Why not just create this functionality as an extension method and use that?
|
|
|
|