winform language localization sample for - winforms

I've the following code to convert the controls in static mode i.e by writing the translated string(french,german etc) and saving the resource file and calling it back. How ever if I need to translate dynamically(including the user-inputs), say like how google translator works. I need to implement the same in offline mode. Is there any possibility to access google like translators, which instantly/dynamically translates to the selected language, but offline? Or please suggest me any preferred method.
foreach (Control c in this.Controls)
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(MainForm));
resources.ApplyResources(c, c.Name, new CultureInfo(lang));
}
--
Regards,
Manohar.

I don`t know if it helps you, but here is what I did. It's written in managed c++ /clr you can easyly translat it to c#.
I wrote a little helper calss to manage the translation process
(You can change the language during runtime with this! It will instantly translate the whole form.)
ref class LanguageSwitcher
{
public:
/// <summary>
/// Change language at runtime in the specified form
/// </summary>
[System::Runtime::CompilerServices::Extension]
static void SetLanguage( Form ^form, CultureInfo ^lang )
{
//Set the language in the application
System::Threading::Thread::CurrentThread->CurrentUICulture = lang;
ComponentResourceManager ^resources = gcnew ComponentResourceManager( form->GetType() );
ApplyResourceToControl( resources, form->MainMenuStrip, lang );
ApplyResourceToControl( resources, form, lang );
form->Text = resources->GetString( "$this.Text", lang );
}
private:
static void ApplyResourceToControl( ComponentResourceManager ^resources, Control ^control, CultureInfo ^lang )
{
for each( Control ^c in control->Controls )
{
ApplyResourceToControl( resources, c, lang );
String ^text = resources->GetString( c->Name + ".Text", lang );
if( text != nullptr )
c->Text = text;
}
}
static void ApplyResourceToControl( ComponentResourceManager ^resources, MenuStrip ^menu, CultureInfo ^lang )
{
if(menu != nullptr)
for each( ToolStripItem ^m in menu->Items )
{
String ^text = resources->GetString( m->Name + ".Text", lang );
if( text != nullptr )
m->Text = text;
}
}
};
This is how it is used:
System::Globalization::CultureInfo^ lang = cli::safe_cast<System::Globalization::CultureInfo^ >(langCombo->SelectedItem);
LanguageSwitcher::SetLanguage(this,lang);
Hope this helps!

Related

Extending classes in C++ (System.Windows.Forms.TextBox)

In C#, I often like to create a custom class called "IntTextBox" which only allows valid integers to exist in the "Text" property.
public class IntTextBox : TextBox
{
string origin = "0";
//A string to return to if the user-inputted text is not an integer.
public IntTextBox()
{
Text = "0";
TextChanged += new EventHandler(IntTextBox_TextChanged);
}
private void IntTextBox_TextChanged(object sender, EventArgs e)
{
int temp;
if(int.TryParse(Text,out temp))
//If the value of "Text" can be converted into an integer.
{
origin = Text;
//"Save" the changes to the "origin" variable.
}
else
{
Text = origin;
//Return to the previous text value to remove invalidity.
}
}
}
I tried to imitate this in C++ and no errors are apparent, however when I attempt to add it to my form, Visual Studio says "Failed to load item 'IntTextBox'. It will be removed from the toolbox. This is the code I've tried so far.
public ref class IntTextBox : public System::Windows::Forms::TextBox
{
public:
IntTextBox()
{
Text = "0";
TextChanged += gcnew System::EventHandler(this, &AIMLProjectCreator::IntTextBox::IntTextBox_TextChanged);
}
private:
String^ origin = "0";
System::Void IntTextBox_TextChanged(System::Object^ sender, System::EventArgs^ e)
{
int temp;
if (int::TryParse(Text, temp))
{
origin = Text;
}
else
{
Text = origin;
}
}
};
Most likely your C++/CLI project is set up to produce a mixed-mode assembly, which is partly CPU-independent CIL (MSIL), and partly native code. The native code is architecture-specific, which means you have to recompile it for either 32-bit (x86) or 64-bit (x64).
If the C++/CLI DLL is a different architecture from Visual Studio, the designer can't load it.
Try compiling for x86 in order to use design mode.

How do you determine (WinForms) control type in UITestControl?

I'm trying to make custom properties for controls available in Coded UI Tests and every example I've found is totally useless.
For instance: http://msdn.microsoft.com/en-us/library/hh552522.aspx
public override int GetControlSupportLevel(UITestControl uiTestControl)
{
// For MSAA, check the control type
if (string.Equals(uiTestControl.TechnologyName, "MSAA",
StringComparison.OrdinalIgnoreCase) &&
(uiTestControl.ControlType == "Chart"||uiTestControl.ControlType == "Text"))
{
return (int)ControlSupport.ControlSpecificSupport;
}
// This is not my control, so return NoSupport
return (int)ControlSupport.NoSupport;
}
// Get the property value by parsing the accessible description
public override object GetPropertyValue(UITestControl uiTestControl, string propertyName)
{
if (String.Equals(propertyName, "State", StringComparison.OrdinalIgnoreCase))
{
object[] native = uiTestControl.NativeElement as object[];
IAccessible acc = native[0] as IAccessible;
string[] descriptionTokens = acc.accDescription.Split(new char[] { ';' });
return descriptionTokens[1];
}
// this is not my control
throw new NotSupportedException();
}
This code is entirely worthless if you have 2 different controls that are "Text" controls - there is no way to determine which type of text control it is. The "ControlType" property is very misleading because it does not return the Type of the control as its name suggests. It's more like a control category. How can you determine what the control actually is?
You can use something like this. Hope this helps.
string controlType = control.GetProperty(XamlControl.PropertyNames.ControlType).ToString();

reactivate exiting window using WindowManager

I am using WPF with the currently latest and greatest version of Caliburn.Micro (1.4.1). I use IWindowManager.ShowWindow(...) to open an new modeless window:
private void OpenOrReactivateInfoView()
{
if(this.infoViewModel == null)
{
this.infoViewModel = new InfoViewModel();
}
this.windowManager.ShowWindow(this.infoViewModel);
}
Instead of opening a new window each time when OpenOrReactivateInfoView() is called, I would like to check whether the window ist still open and if it is, the existing window should just regain focus.
What would we be a good Calibrun.Micro-way to solve this? I sure would like to avoid keeping a reference to the window (or any UIElement for that matter) itself in the viewmodel. Also note that this is a common behavior for a lot of modeless dialogs, so it is preferred solve this in a generic reusable way.
Does Caliburn.Micro already have means for this built in?
The WindowManager source code always creates a new window, so what you really want to do is only use the WindowManager.ShowWindow method if you actually intend to create a new window.
The first thing you want to do is hold a persistent reference to your view model like this:
private readonly InfoViewModel infoViewModel = new InfoViewModel();
private void OpenOrReactivateInfoView()
{
this.windowManager.ShowWindow(this.infoViewModel);
}
Then, in your view model, create a method called Focus or whatever you want like this:
public void Focus()
{
var window = GetView() as Window;
if (window != null) window.Activate();
}
Then revisit your OpenOrReactivateInfoView() method make a slight adjustment like this:
private void OpenOrReactivateInfoView()
{
if (!this.infoViewModel.IsActive)
this.windowManager.ShowWindow(this.infoViewModel);
else
this.infoViewModel.Focus();
}
This method worked for me.
A fairly straightforward way to keep track of your windows without actually
having to implement IViewAware would be to keep a dictionary of weak references
to your ViewModels and Views that go together and then checking if you already
have an existing Window or not. Could be implemented either as a decorator to
the WindowManager, subclass or extension.
Something as simple as the following should do the trick assuming you don't
actually plan on opening enough windows that even the dead WeakReferences
would impact performance. If it is going to be long running it shouldn't be
that hard to implement some sort of cleanup.
public class MyFancyWindowManager : WindowManager
{
IDictionary<WeakReference, WeakReference> windows = new Dictionary<WeakReference, WeakReference>();
public override void ShowWindow(object rootModel, object context = null, IDictionary<string, object> settings = null)
{
NavigationWindow navWindow = null;
if (Application.Current != null && Application.Current.MainWindow != null)
{
navWindow = Application.Current.MainWindow as NavigationWindow;
}
if (navWindow != null)
{
var window = CreatePage(rootModel, context, settings);
navWindow.Navigate(window);
}
else
{
var window = GetExistingWindow(rootModel);
if (window == null)
{
window = CreateWindow(rootModel, false, context, settings);
windows.Add(new WeakReference(rootModel), new WeakReference(window));
window.Show();
}
else
{
window.Focus();
}
}
}
protected virtual Window GetExistingWindow(object model)
{
if(!windows.Any(d => d.Key.IsAlive && d.Key.Target == model))
return null;
var existingWindow = windows.Single(d => d.Key.Target == model).Value;
return existingWindow.IsAlive ? existingWindow.Target as Window : null;
}
}
I have come up with this extension method. It works but I am not particulary happy with it, it is still somewhat hackish.
It is clearly a designsmell that this extension has to make so many assumption about the model (do you see also those nasty exceptions?).
using System;
using System.Collections.Generic;
using Caliburn.Micro;
public static class WindowManagerExtensions
{
/// <summary>
/// Shows a non-modal window for the specified model or refocuses the exsiting window.
/// </summary>
/// <remarks>
/// If the model is already associated with a view and the view is a window that window will just be refocused
/// and the parameter <paramref name="settings"/> is ignored.
/// </remarks>
public static void FocusOrShowWindow(this IWindowManager windowManager,
object model,
object context = null,
IDictionary<string, object> settings = null)
{
var activate = model as IActivate;
if (activate == null)
{
throw new ArgumentException(
string.Format("An instance of type {0} is required", typeof (IActivate)), "model");
}
var viewAware = model as IViewAware;
if (viewAware == null)
{
throw new ArgumentException(
string.Format("An instance of type {0} is required", typeof (IViewAware)), "model");
}
if (!activate.IsActive)
{
windowManager.ShowWindow(model, context, settings);
return;
}
var view = viewAware.GetView(context);
if (view == null)
{
throw new InvalidOperationException("View aware that is active must have an attached view.");
}
var focus = view.GetType().GetMethod("Focus");
if (focus == null)
{
throw new InvalidOperationException("Attached view requires to have a Focus method");
}
focus.Invoke(view, null);
}
}

Advisable to touch the codes in Designer.cs file?

Is it advisable for me to touch the designer.cs file for my windows form application? As I am referencing the labels to my settings file, I plan to code it in such a way that if my settings file shows
int startup = 0;
the code handler for my combo box selection would be
if (settingObject.bootOnStartup == 0)
{
comboStartup.SelectedIndex = 0;
}
else
{
comboStartup.SelectedIndex = 1;
}
it does works for its function but it sort of crashes the design window.
Don't modify the .designer.cs files, ever. Whatever you do in it, it will be overwritten the next time you edit your Form in the designer, so you will have to do it again. I don't see any reason not to put this code in the Form constructor or the Load event...
Your last sentence is the answer. If anything needs special treatment, do it in the user part of the partial class. Even if in your case (I'm speculating) this would require creating a ComboBox manually before the designer code runs.
The only time I touch the designer code is when I simply and quickly want to change something that I'm sure will survive the code generation of VS, e.g. a property name in a binding.
The Designer.cs file tells you not to modify:
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent( ) {
/* ...control customization from designer... */
}
If you have modifications then make those in your Form constructor after InitializeComponent:
public MainForm( ) {
InitializeComponent( );
if (settingObject.bootOnStartup == 0) {
comboStartup.SelectedIndex = 0;
} else {
comboStartup.SelectedIndex = 1;
}
}
... or, on a this.Load event:
public MainForm( ) {
InitializeComponent( );
this.Load += (s, e) => {
if (settingObject.bootOnStartup == 0) {
comboStartup.SelectedIndex = 0;
} else {
comboStartup.SelectedIndex = 1;
}
};
}

WinForms Interop, Drag & Drop from WinForms -> WPF

I'm trying to drag data from the Winforms portion of my application on a WPF controls that's contained inside an "ElementHost". And it crashes when I try doing so.
Trying the same thing but from Winforms to Winforms works fine. (See example code below)
I need help on making this work... have any clues what I'm doing wrong?
Thanks!
Example:
In the sample code below, I'm just trying to drag a custom MyContainerClass object created when initating the drag on the label control on a 1) System.Windows.Forms.TextBox (Winforms) and 2) System.Windows.TextBox (WPF, added to an ElementHost).
Case 1) works fine but case 2) is crashing when trying to retrieve the drop data using GetData(). GetDataPresent("WindowsFormsApplication1.MyContainerClass") returns "true" so In theory, I should be able to retrive my drop data of that type like in Winforms.
Here is the stack trace of the crash:
"Error HRESULT E_FAIL has been returned from a call to a COM component" with the following stack trace:
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Windows.Forms.DataObject.GetDataIntoOleStructs(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.Forms.DataObject.System.Runtime.InteropServices.ComTypes.IDataObject.GetDataHere(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.Forms.DataObject.System.Runtime.InteropServices.ComTypes.IDataObject.GetData(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.DataObject.OleConverter.GetDataInner(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.DataObject.OleConverter.GetDataFromOleHGLOBAL(String format, DVASPECT aspect, Int32 index)
at System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(String format, DVASPECT aspect, Int32 index)
at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert, DVASPECT aspect, Int32 index)
at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert)
at System.Windows.DataObject.GetData(String format, Boolean autoConvert)
at System.Windows.DataObject.GetData(String format)
at WindowsFormsApplication1.Form1.textBox_PreviewDragEnter(Object sender, DragEventArgs e) in WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs:line 48
Here is some code:
// -- Add an ElementHost to your form --
// -- Add a label to your form --
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.Windows.Controls.TextBox textBox = new System.Windows.Controls.TextBox();
textBox.Text = "WPF TextBox";
textBox.AllowDrop = true;
elementHost2.Child = textBox;
textBox.PreviewDragEnter += new System.Windows.DragEventHandler(textBox_PreviewDragEnter);
System.Windows.Forms.TextBox wfTextBox = new System.Windows.Forms.TextBox();
wfTextBox.Text = "Winforms TextBox";
wfTextBox.AllowDrop = true;
wfTextBox.DragEnter += new DragEventHandler(wfTextBox_DragEnter);
Controls.Add(wfTextBox);
}
void wfTextBox_DragEnter(object sender, DragEventArgs e)
{
bool dataPresent = e.Data.GetDataPresent("WindowsFormsApplication1.MyContainerClass");
// NO CRASH here!
object data = e.Data.GetData("WindowsFormsApplication1.MyContainerClass");
}
void textBox_PreviewDragEnter(object sender, System.Windows.DragEventArgs e)
{
bool dataPresent = e.Data.GetDataPresent("WindowsFormsApplication1.MyContainerClass");
// Crash appens here!!
// {"Error HRESULT E_FAIL has been returned from a call to a COM component."}
object data = e.Data.GetData("WindowsFormsApplication1.MyContainerClass");
}
private void label1_MouseDown(object sender, MouseEventArgs e)
{
label1.DoDragDrop(new MyContainerClass(label1.Text), DragDropEffects.Copy);
}
}
public class MyContainerClass
{
public object Data { get; set; }
public MyContainerClass(object data)
{
Data = data;
}
}
#Pedery & jmayor: Thanks for the suggestions guys! (see my findings below)
After quite a few experimentation, trials and errors, and a bit of "Reflector'ing", I managed to figure out exactly why I was receiving the cryptic error message "Error HRESULT E_FAIL has been returned from a call to a COM component".
It was due to the fact that when dragging data WPF <-> Winforms in a same app, that data has to be Serializable!
I've checked how difficult it would be to transform all of our classes to "Serializable" and I would have a been a real pain for a couple of reasons... one, we would need to practically make all of classes serializable and two, some of these classes have references to Controls! And Controls aren't serializable. So a major refactoring would have been needed.
So... since we wanted to pass any object of any class to drag from/to WPF inside the same application, I decided to create a wrapper class, with the Serializable attribute and implementing ISerializable. I would have 1 contructor with 1 parameter of type "object" which would be the actual drag data. That wrapper, when serializing/de-serializing, would serialize not the object itself... but rather the IntPtr to the object (which we can do since we only want that functionnality inside our 1 instance only application.) See code sample below:
[Serializable]
public class DataContainer : ISerializable
{
public object Data { get; set; }
public DataContainer(object data)
{
Data = data;
}
// Deserialization constructor
protected DataContainer(SerializationInfo info, StreamingContext context)
{
IntPtr address = (IntPtr)info.GetValue("dataAddress", typeof(IntPtr));
GCHandle handle = GCHandle.FromIntPtr(address);
Data = handle.Target;
handle.Free();
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
GCHandle handle = GCHandle.Alloc(Data);
IntPtr address = GCHandle.ToIntPtr(handle);
info.AddValue("dataAddress", address);
}
#endregion
}
To keep the IDataObject functionnality, I created the following DataObject wrapper:
public class DataObject : IDataObject
{
System.Collections.Hashtable _Data = new System.Collections.Hashtable();
public DataObject() { }
public DataObject(object data)
{
SetData(data);
}
public DataObject(string format, object data)
{
SetData(format, data);
}
#region IDataObject Members
public object GetData(Type format)
{
return _Data[format.FullName];
}
public bool GetDataPresent(Type format)
{
return _Data.ContainsKey(format.FullName);
}
public string[] GetFormats()
{
string[] strArray = new string[_Data.Keys.Count];
_Data.Keys.CopyTo(strArray, 0);
return strArray;
}
public string[] GetFormats(bool autoConvert)
{
return GetFormats();
}
private void SetData(object data, string format)
{
object obj = new DataContainer(data);
if (string.IsNullOrEmpty(format))
{
// Create a dummy DataObject object to retrieve all possible formats.
// Ex.: For a System.String type, GetFormats returns 3 formats:
// "System.String", "UnicodeText" and "Text"
System.Windows.Forms.DataObject dataObject = new System.Windows.Forms.DataObject(data);
foreach (string fmt in dataObject.GetFormats())
{
_Data[fmt] = obj;
}
}
else
{
_Data[format] = obj;
}
}
public void SetData(object data)
{
SetData(data, null);
}
#endregion
}
And we are using the above classes like this:
myControl.DoDragDrop(new MyNamespace.DataObject(myNonSerializableObject));
// in the drop event for example
e.Data.GetData(typeof(myNonSerializableClass));
I know I know... it's not very pretty... but it's doing what we wanted. We also created a dragdrop helper class which masks the DataObject creation and has templated GetData functions to retrieve the data without any cast... a bit like:
myNonSerializableClass newObj = DragDropHelper.GetData<myNonSerializableClass>(e.Data);
So thanks again for the replies! You guys gave me good ideas where to look at for possible solutions!
-Oli
I had a "similar" issue some time ago so I can at least tell you what I found out.
It seems .Net is resorting to OLE remoting when drag/drop operations are performed in but the simplest of cases. For some reason GetDataPresent will in these cases be successful and GetData will fail. This is furthermore mystified by the fact that there are several versions of the IDataObject in the .Net framework.
Windows Forms defaults to System.Windows.Forms.IDataObject. However, in your case you could try to give System.Runtime.InteropServices.ComTypes.IDataObject a shot instead. You can also check out my discussion here.
Hope this helps.
Seems wonderfull at first sight. I tried it but got some errors on implementations.
I began to correct some errors when I decided to look for something a little bit more simplier, that do not have pointers (humm I don't like that, particularly with carbage collection, but I have no idea if it could have real impact) and that do not use Interop.
I come up with that. It works for me and I hope it will work for anybody else. It is only intended to be used for local drag drop (inside the same app).
How to use to drag:
DragDrop.DoDragDrop(listBoxOfAvailableScopes, new DragDropLocal(GetSelectedSimulResultScopes()),
DragDropEffects.Copy);
How to use to drop (get):
DragDropLocal dragDropLocal = (DragDropLocal)e.Data.GetData(typeof(DragDropLocal));
SimulResultScopes simulResultScopes = (SimulResultScopes)dragDropLocal.GetObject();
Code:
namespace Util
{
[Serializable]
public class DragDropLocal
{
private static readonly Dictionary<Guid, object> _dictOfDragDropLocalKeyToDragDropSource = new Dictionary<Guid, object>();
private Guid _guid = Guid.NewGuid();
public DragDropLocal(object objToDrag)
{
_dictOfDragDropLocalKeyToDragDropSource.Add(_guid, objToDrag);
}
public object GetObject()
{
object obj;
_dictOfDragDropLocalKeyToDragDropSource.TryGetValue(_guid, out obj);
return obj;
}
~DragDropLocal()
{
_dictOfDragDropLocalKeyToDragDropSource.Remove(_guid);
}
}
}
Maybe the events are in the opposite way. The PreviewDragEnter should be related with the WPFTextBox. Also watch out the DragEventArgs class. There is one in System.Windows.Form ( Windows Form version) and the one under System.Windows( for WPF version).

Resources