Is there a way to automate the set of this property ? we have hundreds of forms that needs to be localized and it will be a nightmare going through all of them setting this property to true.
is there a way to make visual studio set all forms in the solution / project to Localizable = true some how ?
When you create a new Windows Form, it does not have have *.resx file and the related code in the designer.cs file. When you set the Form's Localizable property to True, VS adds the following code to the designer.cs but it also then generates and adds the *.resx file.
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form2));
this.SuspendLayout();
//
// Form2
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "Form2";
this.ResumeLayout(false);
Since VS adds the *.resx file, there is no way to find and replace or cut and paste only code.
I tried to record a VS Macro to automate it however, it would not record changing the Localizable property to True (not sure why)
This temp macro maybe a start for you. You could write get the list of your form filenames and loop through them with the macro code below.
DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
DTE.ActiveWindow.Object.GetItem("WindowsFormsApplication1\WindowsFormsApplication1\Form3.cs").Select(vsUISelectionType.vsUISelectionTypeSelect)
DTE.ActiveWindow.Object.DoDefaultAction()
DTE.Windows.Item(Constants.vsWindowKindProperties).Activate()
It's represented by an entry like the following (adjusted for .NET Framework version) in the form's .resx file:
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
The easiest way to automate toggling all the values to true would probably be to run through the Form subclass files, loading their .resx files as XML to test for the presence of the element, and add it if it isn't. Alternately, you could use a ResXResourceReader and ResXResourceWriter to read and write the file contents.
The custom Designer Attribute we set on the DummyUserControl is only used by more derived classes. Suppose you open the DummyUserControl in the designer. In that case, nothing changes cause it looks for the Designer attribute on the BaseType in this case on the UserControl and ignores the one we specified. It applies to Forms as well. So you need a dummy base class where you just set the Designer Attribute.
public class BaseUserControl : DummyUserControl
{
}
[Designer(typeof(MyCustomDesigner), typeof(IRootDesigner))]
public class DummyUserControl : UserControl
{
}
public class MyCustomDesigner : DocumentDesigner
{
/// <inheritdoc />
public override void Initialize(IComponent component)
{
base.Initialize(component);
}
protected override void PreFilterProperties(IDictionary properties)
{
base.PreFilterProperties(properties);
// We set the Localizable property to true then we return a fake property descriptor to disable changing it in the designer.
var localizableDescriptor = properties["Localizable"] as PropertyDescriptor;
if (localizableDescriptor != null)
{
if (localizableDescriptor.GetValue(Component) as bool? == false)
{
localizableDescriptor.SetValue(Component, true);
}
properties["Localizable"] = new LocalizablePropertyDescriptor(localizableDescriptor);
}
}
/// <summary>
/// A simple wrapper where we disallow to change this property in the designer by marking it ReadOnly.
/// </summary>
public class LocalizablePropertyDescriptor : PropertyDescriptor
{
private readonly PropertyDescriptor _source;
/// <inheritdoc />
public LocalizablePropertyDescriptor(PropertyDescriptor source) : base(source) => _source = source;
/// <inheritdoc />
public override bool CanResetValue(object component) => _source.CanResetValue(component);
/// <inheritdoc />
public override object GetValue(object component) => _source.GetValue(component);
/// <inheritdoc />
public override void ResetValue(object component) { }
/// <inheritdoc />
public override void SetValue(object component, object value) => _source.SetValue(component, value);
/// <inheritdoc />
public override bool ShouldSerializeValue(object component) => true;
/// <inheritdoc />
public override Type ComponentType => _source.ComponentType;
/// <inheritdoc />
public override bool IsReadOnly => true;
/// <inheritdoc />
public override Type PropertyType => _source.PropertyType;
}
}
Related
I am trying to use validation to display validation errors on windows elements (actually text boxes), but I failed to get the text boxes that are not focused/edited to update their validation when conditions for failure changed (neither using INotifyDataErrorInfo nor IDataErrorInfo).
Let's say, TextBox1 validate to Error when TextBox2 holds a specific path. Now after changing the path in TextBox2, TextBox1 should clear its error automatically, but this just did not happen, I always hat to enter the TextBox and change its content for validation to update...
Therefore I intended to use Behaviors in order to bind them to a Validation Boolean value and let the behavior set the TextBox in the appropriate VisualState using the default Validation States (Valid, InvalidFocused, InvalidUnfocused).
This is my Behavior (currently only a PoC so no Dependency Property):
/// <summary>
/// Behavior for setting the visual style depending on a validation value
/// </summary>
public class TextBoxValidationBindingBehavior : BehaviorBase<TextBox>
{
/// <summary>
/// Setup the behavior
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.TextChanged += this.AssociatedObject_TextChanged;
}
/// <summary>
/// Set visual state
/// </summary>
private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = this.AssociatedObject as TextBox;
if (textBox.Text == "Test")
{
VisualStateManager.GoToState(textBox, "Valid", false);
}
else
{
if (textBox.Focus())
{
VisualStateManager.GoToState(textBox, "InvalidFocused", true);
}
else
{
VisualStateManager.GoToState(textBox, "InvalidUnfocused", true);
}
}
}
/// <summary>
/// Clean-up the behavior
/// </summary>
protected override void OnCleanup()
{
this.AssociatedObject.TextChanged -= this.AssociatedObject_TextChanged;
base.OnCleanup();
}
}
And the TextBox definition:
<TextBox Grid.Row = "0"
Grid.Column = "1"
Margin = "0, 2, 0, 2"
VerticalAlignment = "Stretch"
VerticalContentAlignment = "Center"
Text = "{Binding NewBookName}">
<b:Interaction.Behaviors>
<behavior:TextBoxValidationBindingBehavior />
</b:Interaction.Behaviors>
</TextBox>
Setting breakpoints I can see that the code gets called as expected. But the VisualStateManager.GoToState has absolutely no impact on the TextBox!
If I define a template for the text box and set custom VisualStates the behavior will work. However, the point was not to redefine visual states for the TextBox but rather to use the existing states just by associating a Behavior bound top a validation boolean and a message to display...
I'd really appreciate any hint!!! Also, I'd be happy to provide more information if required.
For the time being, I had to give up on just setting the Visual States 😣
I needed to create a Behavior that will when bound to the control add an ad-hoc ValidationRule. In principle:
For the custom validation to work (the point is only to get the default visual style on an error), the TextChanged event needs to disable the validation, update the source, then enable validation and re-update the source for the validation to happen
The IsBindingValid dependency property when changed will also update the source to trigger validation
All in all, this works:
/// <summary>
/// Behavior for setting the visual style depending on a validation value
/// </summary>
public class TextBoxValidationBindingBehavior : BehaviorBase<TextBox>
{
#region Internal Validation Class
/// <summary>
/// A validation rule that validates according to a dependency property binding rather than on control content
/// </summary>
private class BindingValidationRule : ValidationRule
{
#region Initialization
/// <summary>
/// Constructor
/// </summary>
/// <param name="that">Behavior holding this class</param>
public BindingValidationRule(TextBoxValidationBindingBehavior that) { this._that = that; }
#endregion
/// <summary>
/// Reference to behavior holding the object
/// </summary>
private readonly TextBoxValidationBindingBehavior _that;
/// <summary>
/// Flag indication that the next validation check is to be disabled / set to true
/// </summary>
public bool DisableValidationOnce = true;
/// <summary>
/// Validates the control
/// </summary>
/// <param name="value">Value to validate (ignored)</param>
/// <param name="cultureInfo">Culture Information</param>
/// <returns>Returns the <see cref="ValidationResult"/> of this validation check</returns>
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (this._that is { } that)
{
ValidationResult validationResult;
if (that.IsBindingValid || this.DisableValidationOnce)
validationResult = new ValidationResult(true, null);
else
validationResult = new ValidationResult(false, that.ErrorText);
// Re-enable validation
this.DisableValidationOnce = false;
// Set Error Tooltip
that.AssociatedObject.ToolTip = validationResult.IsValid ? null : new ToolTip() { Content = validationResult.ErrorContent };
// return result
return validationResult;
}
else throw new Exception($"Internal TextBoxValidationBindingBehavior error.");
}
}
#endregion
#region DepProp: IsBindingValid
public static readonly DependencyProperty IsBindingValidProperty = DependencyProperty.Register("IsBindingValid", typeof(bool), typeof(TextBoxValidationBindingBehavior), new PropertyMetadata(false, IsBindingValidProperty_PropertyChanged));
public bool IsBindingValid
{
get => (bool)this.GetValue(IsBindingValidProperty);
set => this.SetValue(IsBindingValidProperty, value);
}
private static void IsBindingValidProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBoxValidationBindingBehavior _this)
{
// Avoid unnecessary notification propagation (the prop probably changed du to us updating the source property)
if (_this._isValidating) return;
// Trigger validation
if (_this.AssociatedObject is { } textBox && textBox.GetBindingExpression(TextBox.TextProperty) is { } bindingExpression)
bindingExpression.UpdateSource();
}
}
#endregion
#region DepProp: ErrorText
public static readonly DependencyProperty ErrorTextProperty = DependencyProperty.Register("ErrorText", typeof(string), typeof(TextBoxValidationBindingBehavior), new PropertyMetadata("Error"));
public string ErrorText
{
get => (string)this.GetValue(ErrorTextProperty);
set => this.SetValue(ErrorTextProperty, value);
}
#endregion
#region Private properties
/// <summary>
/// The custom validation rule to handle bound validation
/// </summary>
private BindingValidationRule _bindingValidationRule { get; set; }
/// <summary>
/// Indicate if validation already happening to avoid verbose notifications in the application
/// </summary>
private bool _isValidating;
#endregion
/// <summary>
/// Setup the behavior
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
// Set handler(s)
this.AssociatedObject.TextChanged += this.AssociatedObject_TextChanged;
// Create custom validation rule
this._bindingValidationRule = new BindingValidationRule(this);
// Add rule
if (this.AssociatedObject is { } textBox && BindingOperations.GetBinding(textBox, TextBox.TextProperty) is { } binding)
{
// We must be able to handle updating the source in order to set value bypassing validation
if (binding.UpdateSourceTrigger == UpdateSourceTrigger.PropertyChanged) throw new Exception("Cannot set UpdateSourceTrigger to PropertyChanged when using TextBoxValidationBindingBehavior");
// Add custom validation rule
binding.ValidationRules.Add(this._bindingValidationRule);
}
}
/// <summary>
/// Set visual state
/// </summary>
private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
{
if (this.AssociatedObject is { } textBox && textBox.GetBindingExpression(TextBox.TextProperty) is { } bindingExpression)
{
this._isValidating = true;
// Remove validation before updating source (or validation will prevent source from updating if it errors)
this._bindingValidationRule.DisableValidationOnce = true;
// Update Source
bindingExpression.UpdateSource();
// Ensure we are not disabled (if UpdateSource did not call Validation)
this._bindingValidationRule.DisableValidationOnce = false;
// Trigger validation
bindingExpression.UpdateSource();
this._isValidating = false;
}
}
/// <summary>
/// Clean-up the behavior
/// </summary>
protected override void OnCleanup()
{
this.AssociatedObject.TextChanged -= this.AssociatedObject_TextChanged;
// Remove rule
if (this.AssociatedObject is { } textBox && BindingOperations.GetBinding(textBox, TextBox.TextProperty) is { } binding)
{
binding.ValidationRules.Remove(this._bindingValidationRule);
}
base.OnCleanup();
}
}
And the XAML code:
<TextBox Grid.Row = "0"
Grid.Column = "1"
Margin = "0, 2, 0, 2"
VerticalAlignment = "Stretch"
VerticalContentAlignment = "Center"
Text = "{Binding NewBookName}">
<b:Interaction.Behaviors>
<behavior:TextBoxValidationBindingBehavior IsBindingValid = "{Binding IsValidName}"
ErrorText = "Invalid name or a book with the same name already exists."/>
</b:Interaction.Behaviors>
</TextBox>
However, there are a few things I really don't like about this way of proceeding:
This procedure is very verbose in that it triggers potentially a lot of notification bindings every time it updates the source just to validate the content
It may not be thread-safe?!
While it is theoretically possible to use it with other validation rules, it would probably need a lot of code to get it to work
I find this quite hacky...
I hope this can help others or if one has a better idea: YOU ARE WELCOME!!! 😊
I have a dependency property on a usercontrol that is an enum. I bind to it and set it in the main window view but it does not change.
This is the usercontrol and the icon is the enum
<local:GoogleMaterialIcon Icon="AccountBalance"/>
Here is the enum
public enum Icon
{
_3DRotation,
Accessibility
};
here is the dp
/// <summary>
/// Dependency Property used to back the <see cref="Icon"/> Property
/// </summary>
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon",
typeof(Icon),
typeof(GoogleMaterialIcon),
new PropertyMetadata(null));
and finally the property
public Icon Icon
{
get { return (Icon)GetValue(IconProperty); }
set
{
SetValue(IconProperty, value);
}
}
I place a breakpoint inside the set icon but it never runs. also the enum is in its own file. every time i run it shows me the wrong icon because the dp reverts to the first enum and never updates
update: full code of the usercontrol behind
public partial class GoogleMaterialIcon : UserControl
{
/// <summary>
/// Dependency Property used to back the <see cref="Icon"/> Property
/// </summary>
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon",
typeof(Icon),
typeof(GoogleMaterialIcon),
new PropertyMetadata(null));
/// <summary>
/// Constructor
/// </summary>
public GoogleMaterialIcon()
{
InitializeComponent();
}
/// <summary>
/// Select a predefined icon to use
/// </summary>
public Icon Icon
{
get { return (Icon)GetValue(IconProperty); }
set
{
SetValue(IconProperty, value);
}
}
}
Obviosly under some - at least for me - strange circumstances, even Microsoft only comes up with an solution rather than an explanation.
In your PropertyMetadata you are missing the PropertyChanged-Event
Unfortunately i cannot explain in deep, whats happening here. But using the PropertyChanged-Event of the DependencyProperty seems for me an acceptable workaround.
I created a WPF MVVM app using MEF and Prism 5.0. I have MEF loading a module at startup called MobileRecruiterModule (below). I need to read some settings from App.config (or any config file really) and update the ViewModel properties with those config values so the View can pick them up.
Where is the appropriate place to load settings here? Do I do it in the MEF module (the thing that implements Microsoft.Practices.Prism.Modularity.IModule or in my View?
MobileRecruiterModule.cs
[ModuleExport(typeof (MobileRecruiterModule))]
public class MobileRecruiterModule : IModule
{
/// <summary>
/// The region manager
/// </summary>
[Import] public IRegionManager Region;
/// <summary>
/// Notifies the module that it has be initialized.
/// </summary>
public void Initialize()
{
Region.RegisterViewWithRegion(RegionNames.MainContentRegion, typeof (MobileRecruiterView));
}
...
}
MobileRecruiterView.xaml.cs
[Export("MobileRecruiterView")]
[PartCreationPolicy(CreationPolicy.Shared)]
[RegionMemberLifetime(KeepAlive = false)]
[Export]
public partial class MobileRecruiterView : UserControl
{
[Import]
public MobileRecruiterViewModel ViewModel
{
get { return (MobileRecruiterViewModel)DataContext; }
set { DataContext = value; }
}
[ImportingConstructor]
public MobileRecruiterView(MobileRecruiterViewModel vm)
{
InitializeComponent();
DataContext = vm;
}
}
MobileRecruiterViewModel.cs
[Export]
public class MobileRecruiterViewModel : BindableBase
{
public string DatabaseServer { get; set; }
... and a few other properties that the XAML view binds to ...
}
I would suggest that you should load your settings in ViewModel constructor. Because your ViewModel is the DataContext for the View, you have to initialize it before you show it. I hope that you do not store any BLOB in it, so the time for *.config loading will be small enough to do it on UI thread.
I'm trying to make ValidationRule which depends on some property from (for example) data model.
I have TextBox with validator which have to know about the model object "Scheme". I've tryed to add Scheme into Resources but this didn't work. And after I've found some solution relying on dependency properties.
According to this http://dedjo.blogspot.com/2007/05/fully-binded-validation-by-using.html I've made:
/// <summary>
/// Check text value for emptiness and uniqueness
/// </summary>
public class EmptyAndUnique : ValidationRule
{
public UniqueChecker UniqueChecker { get; set; }
public string ErrorMessage { get; set; }
public override ValidationResult Validate(object value,
CultureInfo cultureInfo)
{
string inputString = (value).ToString();
var result = new ValidationResult(true, null);
// Check uniqueness
if(this.UniqueChecker.Scheme.Factors.Any(f => f.Uid == inputString))
{
result = new ValidationResult(false, this.ErrorMessage);
return result;
}
// Check emptiness
if (inputString.Trim().Equals(string.Empty))
{
result = new ValidationResult(false, this.ErrorMessage);
return result;
}
return result;
}
}
/// <summary>
/// Wrapper for DependencyProperty. (trick)
/// </summary>
public class UniqueChecker : DependencyObject
{
public static readonly DependencyProperty SchemeProperty =
DependencyProperty.Register("Scheme", typeof(Scheme),
typeof(UniqueChecker), new FrameworkPropertyMetadata(null));
public Scheme Scheme
{
get { return (Scheme)GetValue(SchemeProperty); }
set { SetValue(SchemeProperty, value); }
}
}
This does not work either.
1) According to article:
Scheme="{Binding ElementName=expressionFactorEditorWindow, Path=Scheme}"
this does not work because:
cos our dependency object is not part
of logical tree, so you can not use
ElementName or DataContext as source
for internal data binding.
But why it's not part of logical tree?
2) How can I bind properties of my ValidationRule to some dynamic resources
UPDATE
While watching for better solution I made this:
Add Event which checks uniqueness into ValidationRule
Add Handler into Window class
Raise event from ValidationRule and check result from EventArgs
What are you binding to that you are trying to add Validation for. How I usually handle this by having the object I am binding to implement IDataErrorInfo. Then I can put my error handling in that object and have access to anything I need. This would be possible if you are in control of the object you are Binding to.
I'm currently writing DataTemplate for my custom type lets say FootballPlayer. In this template I would like to put ie. Button and make that button when clicked call some of FootballPlayer functions eg. Run().
Is there any simple or complex, but clean way to achieve this kind of behaviour?
The DataTemplate I believe is aware of all the information about my object because DataType is set and clr-namespace is included.
<DataTemplate DataType="{x:Type my:FootballPlayer}">
</DataTemplate>
I suppose there is a clean way to achieve this. Can anyone tell me how?
//edit
The solution doesn't have to be clean. Now, after some investigation I'm just looking for any solution that can make a call to function / raise an event on the object being bound.
Yes, there is a clean way to do this. One aspect of using the Model-View-ViewModel pattern in WPF (not that you have to use this) is commanding. WPF Commanding reference
Here is a simplistic but clean and fairly type-safe framework class for exposing commands from your data source object:
using System;
using System.Windows.Input;
namespace MVVM
{
/// <summary>
/// Defines a command that can be bound to from XAML and redirects to a handler function.
/// </summary>
public class ViewModelCommand : ICommand
{
private Action _handler;
public ViewModelCommand(Action handler)
{
_handler = handler;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
#endregion
}
/// <summary>
/// Defines a command that can be bound to from XAML and redirects to a handler function.
/// </summary>
public class ViewModelCommand<T> : ICommand
where T : class
{
private Action<T> _handler;
public ViewModelCommand(Action<T> handler)
{
_handler = handler;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler(parameter as T);
}
#endregion
}
}
Your data source (e.g., FootballPlayer class) then exposes a command property as follows:
/// <summary>
/// Tell the player to run. This particular command takes a string as a parameter.
/// </summary>
public ICommand RunCommand
{
get { return new ViewModelCommand<string>(run); }
}
The implementation function, in the same FootballPlayer class, can then look like this:
/// <summary>
/// Tell the player to run. This particular command takes a string as a parameter.
/// </summary>
public void search(string destination)
{
System.Windows.MessageBox.Show(destination, "Running to destination...");
}
Finally, your XAML has the following databinding:
<Button Content="{Binding PlayerName}" FontSize="16" CommandParameter="{Binding Text, ElementName=txtDestination}" Command="{Binding RunCommand, Source={StaticResource ViewModelDataSource}}" />
(Since you're using a DataTemplate, the sources of the bindings would need to be adjusted; but that's the gist of it. I've used this with great success in a class project - it allowed a very clean separation between the logic and the UI.)
If you set up a generic handler for the event:
<Button Click="FootballPlayer_Run"/>
the DataContext of the e.OriginalSource will be the FootballPlayer object that is used for binding. You can then call Run on that object.
private void FootballPlayer_Run(object sender, RoutedEventArgs e)
{
FrameworkElement ele = e.OriginalSource as FrameworkElement;
if (ele != null)
{
FootballPlayer fp = ele.DataContext as FootballPlayer;
if (fp != null)
{
fp.Run();
}
}
e.Handled = true;
}