I have a WinForms app that I am currently implementing a translation engine in. What I have so far is a bunch of text documents that follow the syntax like:
messages.manualupdate="There is a manual update available for ProgName.\n\nDo you want to update to version {0}.{1}.{2}{3}?"
messages.errorcopy="Clicking OK will copy the error so you can paste it elsewhere!"
messages.error="Error"
messages.notsupported.title="Unsupported client"
messages.notsupported.message="This version is no long supported. Please wait for an update."
I have lots of these for different languages, for example:
messages.manualupdate="é disponibile un'aggiornamento manuale del programma ProgName.\n\nVuoi aggiornare alla versione {0}.{1}.{2}{3}?"
messages.errorcopy="Cliccando OK eseguirete una copia degli errori visualizzati"
messages.error="Error"
messages.notsupported.title="Client non supportato"
messages.notsupported.message="Questa versione non è utilizzabile al momento. attendi il prossimo aggiornamento!"
I then parse this into a DynamicObject which I can access like language.messages.notsupported.error. What I would like to know is if I can somehow link all the controls on the form to use variables from the dynamic object on creation. For instance I have a button on my form that I want to have the text "Error" in. Before the form shows, I set the language variable to the users chosen language, and then when the form shows it simply loads the text from language. Is there a way to do this in the designer rather than having to write a method that is called in the Forms constructor as it seems to me like a little bit of a waste to set all the button text to a value and then change them all when the form loads. I'm looking for a sort of binding, but to the controls Text parameter.
Anyone have any ideas?
MSDN has a walkthrough on string localization that might be of use to you link
Honestly, the approach you are trying to avoid looks best to me. I will suggest you to create a property for the control where you are trying to set the Text. In Set attribute, check for the language selected and get the appropriate text for you.
public string Error
{
set { _errorLabel.Text = value; }
}
private void SetText()
{
if(EnglishSelected)
Error = "English";
}
Regarding waste of time, well, I will just suggest not to set anything in designer and directly set the property in Load form. But I would like to add one more point here that any of the approach will not hit your application speed. First its about making your application expandable and maintainable and then about making it fast. Setting logical things in designer is always a bad practice. If your application is not tiny/small then I will suggest you to follow some design patterns like MVP and move all this logical things in Presenter. Not trying to preach but just suggesting.
And yes, in our company one of team is working in localization part of the application. Using resource may be a better way of doing this.
Hope it helps.
Related
Having an existing WinForms application that I'm migrating to .NET 6 with C# Blazor WebAssembly.
In this WinForms application there is one main window and let's say approximately 50 individual modal dialog box windows (which in turn sometimes show additional modal dialog box windows).
Steps in WinForms
In WinForms to show a dialog it was pretty straightforward:
User clicks on a main menu item "Edit this thing".
A C# click handler is called.
In this click handler, I create an instance of my dialog box class.
The instance is being shown.
When the user closes the dialog box, the instance of the class goes out of scope and is later automatically cleaned up by the GC.
Steps in Blazor
Currently I cannot wrap my head around on how to adapt this concept to a WASM Blazor world.
In my planning I have one single "root" component ("Page") that does not change throughout the whole time that the user interacts with the application. This equals the "main window" concept in WinForms.
For each formerly WinForms dialog box window I plan to create one Blazor component (each with a DxPopup component that shows the form controls as a dialog box).
But I'm not sure on where and how to place these components.
Questions
Should I really place 50+ components right in the root component and show/hide them as needed?
Should I have one single DynamicComponent component that I tell by code which actually component to render?
Any other options?
My fear is to get horrible performance when polluting the component tree with so much components in advance when all I really actually need is one component at a time.
As I mentioned in the comments, Blazored.Modal is a very powerful library for showing dialogs just-in-time by injecting an IModalService in your components, created by Chris Sainty. Example usage:
#inject IModalService Modal
<button #onclick="ShowFormBtnClicked">Show form</button>
#code {
void ShowFormBtnClicked()
{
// FormDialog is a different component (FormDialog.razor).
Modal.Show<FormDialog>("Form dialog title");
}
}
You can also pass parameters to the dialogs and receive results from them (e.g. confirm dialog).
Documentation
This way each dialog is a separate component that is loaded only where and when it's needed. With this library you can avoid having to put all modals inside your components like that:
<Modal #bind-Visible="_modal1Visible">...</Modal>
<Modal #bind-Visible="_modal2Visible">...</Modal>
<Modal #bind-Visible="_modal3Visible">...</Modal>
...
...
#code {
private bool _modal1Visible;
private bool _modal2Visible;
private bool _modal3Visible;
...
}
I believe good practice is to render only when it's needed.
When it comes to component based frameworks, you need to leverage off your components as much as possible. Dynamic components are amazing for this, and can really improve development speed.
I recommend not using dialogs/modals, bar special occasions. I see it being used a lot, and quite frankly, I believe it to be bad for user experience and performance. Only render what is needed at that time, especially in WASM since the client is doing all the UI computing.
In your instance I recommend starting with the basics as you work on this application, if done correctly, this foundation will improve your development speed 10 fold.
Need to put in a textbox? Create a component, and doing so you will learn the ins and outs of Blazor a lot quicker. You will also realise the dos and don'ts.
Ok now you have a textbox, next up is a form item to contain the textbox. Create a component for the form item.
Now you can wrap your textbox in a form item. So later, if you need to change anything, be it logic or CSS, you only need to update a single component.
Grow your component library from there, and with that your understanding of Blazor.
Now to the subject at hand:
It is good to hide what isn't used. Wrap code blocks in if statements, and render them when needed. There's also no reason not to navigate to a new page. If you have a lot going on in a single page component, I recommend splitting what you have into smaller components. It's easier to work through, and a lot easier to maintain.
At the end of the day you can have:
#if (_showForm1) {
<MyFormComponent Heading="Form 1">
<MyFormItem Label="Value 1">
<MyInputText #bind-Value="#form1.Value1" />
</MyFormItem>
</MyFormComponent>
}
Important note: Not every blazor component library is good. I ran across MatBlazor and I was astonished at the bad implementations within this library. It is an overcomplicated mess. It is open source on GitHub, so you can have a look.
Keep whatever you do as simple as possible. Don't make a component a jack of all trades. Your components must be very specific, and focused around performance. A generic component is not a jack of all trades component if it has a specific focus. Example, an input component for numeric values can be generic to support int, long, decimal etc. But an input component that can work with string, DateTime and int, is a jack of all trades. This should be obvious...but I've seen some things.
This is a follow-up on my journey. I took a longer look at the recommended Blazor.Modal but initially didn't like their own dialog HTML markup.
So I started asking a similar question in the DevExpress support center on how to do the same as Blazored.Modal with DxPopup. And I did get some rather decent replies, basically the support guy providing me with a full solution on how to do something similar to what Blazored.Modal does.
Later, I figured out that Blazored.Modal lets you completely replace their UI with a custom one (example file 1 and file 2).
So I am now going this way: Use Blazored.Modal and provide my own UI through DxPopup.
Example
File "UweKeimPopupTest.razor":
<DxPopup Visible="true"
ShowHeader="true"
ShowFooter="true"
HeaderText="Edit element">
<BodyTemplate>
<div class="p-3" style="height: 200px">
<p>#Message</p>
</div>
</BodyTemplate>
<FooterContentTemplate>
<DxButton RenderStyle="ButtonRenderStyle.Primary" Text="Store" Click="#Close" />
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Text="Cancel" Click="#Cancel" />
</FooterContentTemplate>
</DxPopup>
#code
{
[CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; } = default!;
[Parameter] public string? Message { get; set; }
async Task Close() => await BlazoredModal.CloseAsync(ModalResult.Ok(true));
async Task Cancel() => await BlazoredModal.CancelAsync();
}
File "index.razor":
<DxButton Text="Blazored.Modal with DxPopup" Click="#ShowModalCustomLayout" />
#code
{
[CascadingParameter] public IModalService Modal2 { get; set; } = default!;
void ShowModalCustomLayout()
{
var options = new ModalOptions { UseCustomLayout = true };
var parameters = new ModalParameters {
{ nameof(UweKeimPopupTest.Message), "Hello custom modal." } };
Modal2.Show<UweKeimPopupTest>("Custom Layout", parameters, options);
}
}
For me, this combines the advantages of having well tested libraries Blazored.Modal and DevExpress Blazor as well as the core functionality to use ad hoc popup window creating and still being able to use the DevExpress popup implementation DxPopup.
See also this related question of mine in the Blazored.Modal issue tracker.
Does anyone knows how to implement razor syntax to be rendered when using CKediotr. I want to enter c# code in CKEditor but Im not able to do that because it renders all content as a text.
Sample:
I want to enter e.g. #DateTime.Now.Year inside ckeditor.
and other more complex types.
Thanks,
TinyMCE, (F)CKEditor, et al are HTML editors, and are not designed for C# (or PHP, ASP, CFM...) functions. While you could possible right something for evaluating the text and figuring out what you need to do, it becomes a royally complex PIA. There are two ways that I have seen that work with decent results.
The first method would be to have the output from your (CK) Editor saved as a partial view, and then calling that inside of a parent view. The problem with this method is that if someone who does not know Razor makes an error it will kill the page. Same thing occurs for other programming errors.
The second method would be to create placeholders for common items, and then doing an evaluation method for replacements.
string BodyContent = GetPageContent(PageID); // whatever to grab CKEditor content
BodyContent = BodyContent.Replace("##Year##", DateTime.Now.ToString("yyyy"));
// other replacements here
And then on the view you would just call that variable accordingly. It is limited as to what you can do, but that isn't always a bad thing.
I am busy developing a WinRT Application.
I want to access the value of RichEditBox defined in page BasicPage1.xaml into the code behind the page BasicPage2.xaml i.e in BasicPage2.xaml.cs?
Is there anyway to get the value of the RichEditBox(defined in BasicPage1.xaml) in BasicPage2.xaml.cs ?
Thanks in anticipation.
Are you familiar with MVVM? Basically the idea is to not rely to much on the control layer for business data, instead share these information on another layer, in this case the model or view model.
So lets say you want to want to load a project and have a dialog with a textbox containing the path to a project, which the user can modify. So you would store the path in a model called ProjectInformation, this object you can now pass to other views (to be more precise, view models and then views) and use the data there. The important part here is lifetime, your model propably lives much longer than your view, so the data is stored and reused in the places where its necessary.
A simple way to do this is to give your textbox a name in the XAML and then access that textbox via the name in the code behind.
<TextBox Name="myTextBox"/>
then in the code behind you can do this
myTextBox.Text = "blah";
A better way is to use binding so that updating the textbox automatically updates the property you are bound to. Have a look at this post textbox binding example
For a rich edit textbox you should be able to do this:
set
myTextBox.Document.SetText(Windows.UI.Text.TextSetOptions.None, "Here is text");
get
string value = string.Empty;
myTextBox.Document.GetText(Windows.UI.Text.TextGetOptions.AdjustCrlf, out value);
See this post for more information
Do you need to send it through when navigating to the other page? Then you can do it like this:
this.Frame.Navigate(typeof(BasicPage2),textbox.Text);
and at the BasicPage2.xaml.cs:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var textbox= e.Parameter;
...
}
But i also highly recommend using MVVM in your application. With MVVMLight you can implement this quite easy and quick.
I have 2 questions regarding a tutorial that I am going through.
Q1.
Through the tutorial they use a datasource
Using the data in the app
To use the data in the app, you create an instance of the data source
as a resource in App.xaml. You name the instance feedDataSource.
BR211380.wedge(en-us,WIN.10).gifTo add a resource to an app
Double-click App.xaml in Solution Explorer. The file opens in the XAML editor.
Add the resource declaration, <local:FeedDataSource x:Key="feedDataSource"/>, to the root ResourceDictionary, after the
MergedDictionaries collection.
and then they use it in the OnLaunch method.
var connectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (connectionProfile != null)
{
FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
if (feedDataSource != null)
{
if (feedDataSource.Feeds.Count == 0)
{
await feedDataSource.GetFeedsAsync();
}
}
}
I am wondering why do they store it in resource? Wy not just create an instance of the class and get the results from it?
Q2.
Later down the article they use this datasource items with "grid view items". I seen this done in their other template projects. I am wondering is there the standard way of making your interface?
At first I thought maybe just drop some image buttons on the screen and hook up their click events but now I am not sure.
The XAML Resource essentially does create an instance for you and makes it available in the Resources collection, so you could instantiate the class yourself. Having it as a resource keeps this object around and makes it accessible across the various pages in your application. You could certainly create the class explicitly, and if you enforce the singleton pattern on it, it would be semantically equivalent.
I'm not sure I see the context of your second question in the tutorial, but in general the pattern you are seeing is Model-View-ViewModel (MVVM), which is the de facto standard pattern for Windows Store apps. feedDataSource is providing the model and portions of that are assigned to DefaultViewModel, which is the DataContext for all of the binding markup in the XAML pages, which are the views. The idea behind this to separate your data from your model, so that when you do things like load a new data feed, etc., all you need to do is change the data source, and all of the data binding markup will automatically reflect the new data in your user interface.
If you find yourself writing code that looks like TextBox.Text = "My text", then you're deviating from the pattern.
Is there an easy way to add an Text field to an UIAlertView an get the text out of it?
The input fields in UIAlertView are supported natively by iOS SDK 5 and higher. If you need to support version 4, you'll need a bit of hacking.
I once made some sample code for Montouch. Not very clean but it should give you the idea:
http://wildsau.net/post/2011/01/28/iOS-UIAlertView-with-a-UITextField-a-MonoTouch-implementation.aspx
And, yes, this will be approved by Apple without problems.
As of iOS5 you can add textfields to UIAlertViews including secure password fields. Here is a tutorial link:
http://mobile.tutsplus.com/tutorials/iphone/ios-5-sdk-uialertview-text-input-and-validation/
iOS 5.0 introduced UIAlertViewStyle. There are 4 to choose from, the default one we always had, plus 3 others that include UITextFields.
If you want to support iOS versions prior to 5.0 though, you can customize these alertViews yourself (I did this in the app I just released). You can add either/both UITextFields and UILabels this way.
I implemented the alertView like this:
UIAlertView *changeEmailAlert = [[UIAlertView alloc] initWithTitle:#"Change Email Address" message:#"\n\n" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
The message (\n\n) has line breaks to make enough room to fit the size of my UILabel and UITextField.
Then, just add the UILabel and UITextField as subviews of the UIAlertView, the same as you would add a subview anywhere else.
Here is the important part: You need to save the text in the UITextField before dismissing the alertView. I use -(void)textFieldDidEndEditing:(UITextField *)textField to get the entered text and save it in a variable that will be accessible later.
If you need a non-iOS5-only solution, UIAlertViews are just views like anything else. You can subclass them, add additional properties and subviews.
There's nothing stopping you from creating a UIAlertView subclass that has a textfield property, implements the textfield delegate protocol and adds the textfield to its own view hierarchy when you instantiate it.
Getting it to looks nice may be trickier, and doing stuff like moving the other subviews around to make space for the text field may involve some fragile hacks like looping through unnamed subviews within the alert view and grabbing one by index. But this is pretty much the only way to do this on iOS4 and earlier, and plenty of app have taken this approach.