Importing converter from dll into XAML - c#

I have an EnumToBool Converter class in a dll file MicroMVVM. I want to import and create a resource of this class in XAML of my WPF application. Following is how my declaration in XAML looks like:
<Window x:Class="WpfMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfMVVM"
xmlns:micro="clr-namespace:MicroMVVM;assembly=MicroMVVM"
Title="MainWindow" Height="350" Width="525" ContentRendered="Window_ContentRendered">
<Window.DataContext>
<!-- Declaratively create an instance of our SongViewModel -->
<local:SabrixQAViewModel />
</Window.DataContext>
<Window.Resources>
<micro:EnumToBoolExtension x:Key="EnumToBool" />
</Window.Resources>
I am getting error in "clr-namespace". The error is "Undefined CLR namespace.The 'clr-namespace' URI refers to a namespace 'MicroMVVM'that is not included in the assembly.
I have added a reference of MicroMVVM.dll in my solution and i am using other classes of the dll in the ViewModel. However, I am getting error while trying to use it in XAML. Please help.
Following is how the Converter class looks inside MicroMVVM:
namespace MicroMvvm
{
public enum ValidationMode
{
GSS,
Digital
}
[ValueConversion(typeof(bool), typeof(Enum))] //This is converting boolean value to a value in Enum
public class EnumToBoolExtension : MarkupExtension, IValueConverter
{
#region IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return parameter.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)value) == true ? parameter : DependencyProperty.UnsetValue;
}
#endregion
#region MarkupExtension
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
#endregion
}
}

Try to change this:
xmlns:micro="clr-namespace:MicroMVVM; assembly=MicroMVVM"
to:
xmlns:micro="clr-namespace:MicroMvvm;assembly=MicroMVVM"

There is a space between semicolon and the word assembly in your prefix declaration. That will make syntax wrong. Try to remove that space and try again.

Related

Value converter change back to source

I am using xml binding with my wpf controls, the XMLDocument is an exposed property of ViewModel. Here is the code:
public class ViewModel : ViewModelBase
{
private XmlDocument _xmlDataProvider;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
base.RaisePropertyChangedEvent("Name");
}
}
public XmlDocument XmlDataProvider
{
get { return _xmlDataProvider; }
set
{
_xmlDataProvider = value;
base.RaisePropertyChangedEvent("XmlDataProvider");
}
}
}
And my XAML code Looks like this:
<UserControl x:Name="ctrlTemplate" x:Class= "CtrlTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFControl.UI"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:xckt="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
mc:Ignorable="d"
DataContext="{DynamicResource ViewModel}">
<UserControl.Resources>
<local:ViewModel x:Key="ViewModel" />
</ResourceDictionary>
</UserControl.Resources>
The following control is binded to a node in my xml:
<DatePicker DataContext="{Binding Path=XmlDataProvider}" SelectedDate="{Binding XPath=dataDocument/loan/paymentDates/paymentDate[1], Converter={StaticResource NullToDateConverter}, UpdateSourceTrigger=PropertyChanged}"/>
My converter in the code segment is as follows:
public class NullToDateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (String.IsNullOrEmpty(value.ToString()))
{
return DateTime.Now.Date;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.ToString();
}
}
The converter works as intended, if the value of the node is empty. It sets the value of the datetime control to current value.
But I am facing the issue, that if the user for any reason does not change the value of datepicker and tries to save the xml, the value of the node in the xml remains null. What is the best way to do so?
WPF won't update the source if it doesn't think that the target's value is different from the source's. I.e. if the target value doesn't change.
You can, however, force WPF to update the source by calling the BindingExpression.UpdateSource() method. Without a good, minimal, complete code example that reliably reproduces the problem, it's impossible to say specifically how you'd incorporate this into your code. One obvious option would be to call it when the XML is to be saved (i.e. just before).
That might look something like this:
BindingOperations
.GetBindingExpression(datePicker1, DatePicker.SelectedDateProperty)
.UpdateSource();
That assumes, of course, that you name your DatePicker control as datePicker1.
This will ensure that whatever the current value of SelectedDate, it is copied back to the original source for the binding (i.e. the path in your XML).

Why would I get a "BoolToRowHeightConverter is not supported in a Windows Presentation Foundation(WPF) project error in xaml?

Why would I get a "BoolToRowHeightConverter is not supported in a Windows Presentation Foundation(WPF) project error in xaml?
I was using a converter to convert rowheight to * and Auto in a grid based on the expander's IsExpanded property.
Code in xaml:
<RowDefinition Height="{Binding IsExpanded, ElementName=Expander5, Converter={x:Static BoolToRowHeightConverter.Instance}}"/>
Code in xaml.cs:
public class BoolToRowHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((bool)value) return new GridLength(1, GridUnitType.Star);
else
return GridLength.Auto;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Typically, IValueConverters are used like this:
a) Add a namespace in your XAML page that references your converter class... usually it looks something like this:
xmlns:Converters="clr-namespace:WpfApplication1.Converters"
b) Add an instance of your converter class into the Resources section of your page (or of App.xaml:
<Window.Resources>
<Converters:BoolToRowHeightConverter x:Key="BoolToRowHeightConverter" />
...
</Window.Resources>
c) Reference your converter instance by the x:Key value that you gave it:
<RowDefinition Height="{Binding IsExpanded, ElementName=Expander5,
Converter={StaticResource BoolToRowHeightConverter}}" />
You have decided to reference the value converter by using the x:Static markup extension ({x:Static BoolToRowHeightConverter.Instance}) but then you also need to provide the actual field or property that you reference (Instance). To do that you need to add it to the BoolToRowHeightConverter class:
public class BoolToRowHeightConverter : IValueConverter
{
// Convert and ConvertBack methods ...
public static readonly BoolToRowHeightConverter Instance = new BoolToRowHeightConverter();
}

WPF: Can't instantiate class in Window.Resources

I'm doing this WPF tutorial and for some reason I get an error when adding a custom SlidersToColorConverter class to resources.
Someone on StackOverflow was doing it exact same way.
MainWindow.xaml:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:SlidersToColorConverter x:Key="whyareyounotworking"/>
</Window.Resources>
</Window>
SlidersToColorConverter.cs:
namespace WpfApplication2
{
class SlidersToColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double red = (double)values[0];
double green = (double)values[1];
double blue = (double)values[2];
return new SolidColorBrush(Color.FromArgb(255, (byte)red, (byte)green, (byte)blue));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Error List:
The name "SlidersToColorConverter" does not exist in the namespace "clr-namespace:WpfApplication2". c:\users\mateusz\documents\visual studio 2013\Projects\WpfApplication2\WpfApplication2\MainWindow.xaml 39 9 WpfApplication2
It looks like the class is private (by default). You must change your definition to
public class SlidersToColorConverter : IMultiValueConverter

Localizing dialogs in MVVM: is it good to reference the resources from the ViewModel?

I've gotten to the point where I need to add localization to my WPF MVVM application (I use Caliburn.Micro + Autofac).
I did some research, and I've found many different ways to accomplish it, but none provide a solution to localize the text of a dialog.
As dialogs I use a DialogViewModel that Caption and Message string properties, and I show it in a DialogView using CM's WindowManager.
What I have atm is something like
this.windowManager.ShowDialog(new DialogViewModel("Hello!", "Hello everybody!!"))
but also things like
this.windowManager.ShowDialog(new DialogViewModel("Hello!", "Hello " + this.Name + "!!"))
I thought I could use a resource string like "Hello {0}!!" and use it this way
this.windowManager.ShowDialog(new DialogViewModel("Hello!", string.Format(languageResources.HelloName, this.Name)))
Is it good to do reference the localization resources from the ViewModel layer?
Resources is the data that uses a View, and my opinion is that is not advisable from the ViewModel refer to resources. On the other hand, if it is a class (may be static) that stores a specific strings, and knows nothing of the View it will be some abstraction that can be in the ViewModel. In any case, you should try to work with the resources on the side View using techniques that I will give, or any other.
Using x:Static Member
In WPF, it is possible to bind static data from a class like this:
<x:Static Member="prefix : typeName . staticMemberName" .../>
Below is an example where the format string is in a class, the format used to display the date and time.
XAML
xmlns:local="clr-namespace:YourNameSpace"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<Grid>
<TextBlock Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat={x:Static Member=local:StringFormats.DateFormat}}"
HorizontalAlignment="Right" />
<TextBlock Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat={x:Static Member=local:StringFormats.Time}}" />
</Grid>
Code behind
public class StringFormats
{
public static string DateFormat = "Date: {0:dddd}";
public static string Time = "Time: {0:HH:mm}";
}
In this case, the StringFormats class be regarded as a resource, although actually it is a normal class. For more information, please see x:Static Markup Extension on MSDN.
Using Converter
If you have the resources stored in Application.Current.Resources and need to add some logic, in this case, you can use the converter. This example is taken from here:
XAML
<Button Content="{Binding ResourceKey, Converter={StaticResource resourceConverter}}" />
Code behind
public class StaticResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var resourceKey = (string)value;
// Here you can add logic
return Application.Current.Resources[resourceKey];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
Note: In the converter, it is better not to use heavy logic, because it can affect the performance. For more complex logic, see below.
Attached Behavior
Attached behavior should be used for complex actions with visual elements when no x:Static Member and converter is not helped. Attached behavior is very powerful and convenient solution that fully satisfies the MVVM pattern, which can also be used in the Blend (with a pre-defined interface). You can define an attached property in which property handler to access elements and to its resources.
Examples of implementation attached behaviors, see below:
Set focus to a usercontrol when it is made visible
Animated (Smooth) scrolling on ScrollViewer
Setting WindowStartupLocation from ResourceDictionary throws XamlParseException
Example with converter
App.xaml
Here I store strings for each culture.
<Application x:Class="MultiLangConverterHelp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="MainWindow.xaml">
<Application.Resources>
<sys:String x:Key="HelloStringEN">Hello in english!</sys:String>
<sys:String x:Key="HelloStringRU">Привет на русском!</sys:String>
</Application.Resources>
</Application>
MainWindow.xaml
The input is the current culture, which can be obtained within the converter, for simplicity of an example I did so.
<Window x:Class="MultiLangConverterHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MultiLangConverterHelp"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:StaticResourceConverter x:Key="converter" />
<local:TestViewModel x:Key="viewModel" />
</Window.Resources>
<Grid DataContext="{StaticResource viewModel}">
<TextBlock Text="{Binding Path=CurrentCulture, Converter={StaticResource converter}}" />
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class StaticResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var currentCulture = (string)value;
if (currentCulture.Equals("EN-en"))
{
return Application.Current.Resources["HelloStringEN"];
}
else if (currentCulture.Equals("RU-ru"))
{
return Application.Current.Resources["HelloStringRU"];
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
public class TestViewModel : NotificationObject
{
private string _currentCulture = "EN-en";
public string CurrentCulture
{
get
{
return _currentCulture;
}
set
{
_currentCulture = value;
NotifyPropertyChanged("CurrentCulture");
}
}
}
Also, I advise you to learn more simple ways, which is already in the WPF technology:
WPF Localization for Dummies
WPF Globalization and Localization Overview

XAML bind to static method with parameters

I got a static class like the following:
public static class Lang
{
public static string GetString(string name)
{
//CODE
}
}
Now i want to access this static function within xaml as a binding.
Is there such a way for example:
<Label Content="{Binding Path="{x:static lang:Lang.GetString, Parameters={parameter1}}"/>
Or is it necessary to create a ObjectDataProvider for each possible parameter?
Hope someone is able to help me. Thanks in advance!
I get this need too. I "solved" using a converter (like suggested here).
First, create a converter which return the translated string:
public class LanguageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == null)
return string.Empty;
if (parameter is string)
return Resources.ResourceManager.GetString((string)parameter);
else
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
then use it into XAML:
<Window.Resources>
<local:LanguageConverter x:Key="LangConverter" />
</Window.Resources>
<Label Content="{Binding Converter={StaticResource LangConverter},
ConverterParameter=ResourceKey}"/>
Regards.
The right way would be to go the objectdataprovider route. Although if you are just binding to text rather than use a label, I would use a textblock.
<ObjectDataProvider x:Key="yourStaticData"
ObjectType="{x:Type lang:Lang}"
MethodName="GetString" >
<ObjectDataProvider.MethodParameters>
<s:String>Parameter1</s:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<TextBlock Text={Binding Source={StaticResource yourStaticData}}/>

Categories

Resources