Enum localization using Binding and different languages - c#

I try to find solution to output localized enums from resources using Binding.
Now I bind enums by common way like that:
<Page.Resources>
<ObjectDataProvider x:Key="RootConverterType" MethodName="GetValues" ObjectType="{x:Type sys:Enum}" >
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="settingsManager:RootConverterType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ComboBox ItemsSource="{Binding Source={StaticResource RootConverterType}}" SelectedValue="{Binding Path=CameraPosition.Config.UI.ValueConverterType.W, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
This is not localized enums, but I wish to use localization for them (using different languages from resources) and with conversion from localized string to enum in background without ComboBox events and explicit conversion. Is this possible? If yes, could someone provide simple code example please?

I think it is impossible if you import multi xaml files to implement localization.
Because if you import languages to xaml , they are static resources. I suggested you use Binding dynamic resource, and import resources in cs files to initialize resource key.
Xaml Like this:
Content="{DynamicResource UID_AppCommon_MiniPA_Close}"
CS Like this:
this.Resources.MergedDictionaries.Add(your resource file);

I'm using a wrapper struct to solve this problem:
public enum AttributeType {
Bool,
Number,
String
}//AttributeType
public struct AttributeTypeWrapper {
public AttributeTypeWrapper(AttributeType type) {
this.type = type;
}
private AttributeType type;
public AttributeType Type {
get {
return type;
}
set {
type = value;
}
}
public override string ToString() {
switch(type) {
case AttributeType.Bool:
return Properties.Resources.txtBool;
case AttributeType.Number:
return Properties.Resources.txtNumber;
case AttributeType.String:
return Properties.Resources.txtString;
default:
return "Invalid AttributeType";
}
}
}// AttributeTypeWrapper
Note that it is a struct not a class. So it is a value type and can easyly set as SelectedItem of a ComboBox or ListBox for example.
To go a step further, you can implement an IValueConverte for simple Binding:
/// <summary>
/// Convert a AttributeType into its wrapper class to display strings from resources
/// in the selected language
/// </summary>
[ValueConversion(typeof(AttributeType), typeof(AttributeTypeWrapper))]
public class AttributeTypeToWrapperConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return new AttributeTypeWrapper((AttributeType)value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return ((AttributeTypeWrapper)value).Type;
}
}
Then you can bind SelectedItem directly to the enum type:
<AttributeTypeToWrapperConverter x:Key="convertAttrTypeToWrapper"/>
<ComboBox ItemsSource="{Binding Path=DataTypes}"
SelectedItem="{Binding Path=SelectedDataType, Converter={StaticResource convertAttrTypeToWrapper}}"/>
DataTypes is an Array of AttributeTypeWrapper structs. SelectedDataType is of type
AttributeType. (You can convert the ItemsSource as well).
This works pretty fine for me.

I found another way to localize enums:
Here is my class which you can use ase an example:
ru_RU and en_US - resources file names.
public class EnumLocalizationManager : BindableObject
{
public Language language;
private CommonLocalization commonLang;
private ObservableCollection rootCoverterTypes;
public EnumLocalizationManager()
{
commonLang = CommonLocalization.GetInstance;
EnumLanguage = commonLang.Lang;
}
//Коллекция для локализации enum RootConverterType
public static Dictionary<Language, ObservableCollection<string>> RootConverterLocalization = new Dictionary<Language, ObservableCollection<string>>()
{
{
Language.ru_RU, new ObservableCollection<string>()
{
ru_RU.CameraEnumConverterTypeUndefined, ru_RU.CameraEnumConverterTypeAuto, ru_RU.CameraEnumConverterTypeNumber, ru_RU.CameraEnumConverterTypeExponent, ru_RU.CameraEnumConverterTypeDecimal, ru_RU.CameraEnumConverterTypeInteger
}
},
{
Language.en_US, new ObservableCollection<string>()
{
en_US.CameraEnumConverterTypeUndefined, en_US.CameraEnumConverterTypeAuto, en_US.CameraEnumConverterTypeNumber, en_US.CameraEnumConverterTypeExponent, en_US.CameraEnumConverterTypeDecimal, en_US.CameraEnumConverterTypeInteger
}
}
};
//Коллекция для локализации enum ConverterType
public static Dictionary<Language, ObservableCollection<string>> ConverterLocalization = new Dictionary<Language, ObservableCollection<string>>()
{
{
Language.ru_RU, new ObservableCollection<string>()
{
ru_RU.CameraEnumConverterTypeAuto, ru_RU.CameraEnumConverterTypeNumber, ru_RU.CameraEnumConverterTypeExponent, ru_RU.CameraEnumConverterTypeDecimal, ru_RU.CameraEnumConverterTypeInteger
}
},
{
Language.en_US, new ObservableCollection<string>()
{
en_US.CameraEnumConverterTypeAuto, en_US.CameraEnumConverterTypeNumber, en_US.CameraEnumConverterTypeExponent, en_US.CameraEnumConverterTypeDecimal, en_US.CameraEnumConverterTypeInteger
}
}
};
public ObservableCollection<string> RootConverterTypes
{
get { return rootCoverterTypes; }
}
public ObservableCollection<string> ConverterTypes
{
get { return coverterTypes; }
}
public Language EnumLanguage
{
get { return language; }
set
{
language = value;
ChangeEnumLanguage();
}
}
private void ChangeEnumLanguage()
{
if (RootConverterLocalization.ContainsKey(language))
{
rootCoverterTypes = RootConverterLocalization[language];
}
if (ConverterLocalization.ContainsKey(language))
{
coverterTypes = ConverterLocalization[language];
}
RaisePropertyChanged();
RaisePropertyChangedByName("RootConverterTypes");
RaisePropertyChangedByName("ConverterTypes");
}
}
}
BindableObject class is class which incapsulates INotifyPropertyChanged.
First of all - your enums must be numbered (it is needed for ValueConverter)
for ex:
public enum ConverterType
{
Auto = 0,
Number = 1,
Exponential = 2,
Decimal = 3,
Integer = 4
}
public enum RootConverterType
{
Undefined = 0,
Auto = 1,
Number = 2,
Exponential = 3,
Decimal = 4,
Integer = 5
}
and the last part - ValueConvert by itself:
class EnumCameraVariantToLocalizedStringConverter:ConverterBase
{
public EnumCameraVariantToLocalizedStringConverter()
{
}
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)(CameraVariant)value;
}
public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int index = (int)value;
switch (index)
{
case 0:
return CameraVariant.Undefined;
case 1:
return CameraVariant.FirstPerson;
case 2:
return CameraVariant.ThirdPerson;
case 3:
return CameraVariant.Flight;
}
return index;
}
}
I use inheritance from base class just to use makrup extenstions without adding resources for each converter.
And the Binding itself:
<ComboBox Style="{StaticResource CameraMainSelectorStyle}"
ItemsSource="{Binding Source={StaticResource EnumLocalizationManager}, Path=CameraVariant}"
SelectedIndex="{Binding Path=CameraSettingsManager.StartUpCameraModeFilter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={valueConverters:EnumCameraVariantToLocalizedStringConverter}}"
Tag="{Binding Path=CameraSettingsManager.StartUpCameraModeFilter, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
SelectionChanged="StartUpCameraTypeFilter_OnSelectionChanged"/>
Here is binding enum to Combobox. I hope evething is clear. One thing here. If you want to change language on fly, you must add some code for not loosing selected item after language changing:
if (((ComboBox)sender).SelectedIndex < 0)
{
if (((ComboBox) sender).Tag != null)
{
CameraVariant behavior = (CameraVariant) ((ComboBox) sender).Tag;
((ComboBox) sender).SelectedIndex = (int) behavior;
}
}
That all. Looks a little bit scary, but there is nothing hard.

Related

C# WPF MVVM - Binding VisibilityOnLegend or Visibility don't work

The binding on the chart:FastLineBitmapSeries which is part of the SyncFusion package does not work.
How to do it? I have another property that uses the BoolToVisibility converter that works, why not this one?
Here is my code:
Xaml
<chart:FastLineBitmapSeries DataContext="{Binding AllSeries[VT8PvPower]}" Interior="#7f84e8" VisibilityOnLegend="{Binding AllSeriesVisibility[VT10PvPower], Converter={StaticResource BoolToVisibility}, Mode=TwoWay}" />
The DataContext is working fine but not the VisibilityOnLegend
View model
AllSeriesVisibility propertie: (same as AllSeries)
public ObservableDictionary<string, bool> AllSeriesVisibility { get; set; } = new ObservableDictionary<string, bool>();
Content of the properties:
AllSeriesVisibility - Keys
Values:
the values are not always at true like in pic
Converter
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool bValue))
return Visibility.Hidden;
return bValue ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Change the binding modes / change the public property, I tried to put a public bool instead of an ObservableDictionnary but it still doesn't work
We have analyzed your code snippet, we suspect that the classes that contain the AllSeries and AllSeriesVisibility properties are the same.
The remaining binding properties for the series should be in the AllSeries value object when you specify BindingContext as the AllSeries Key object, not in the AllSeries parent class.
Based on your code snippet, we created a simple sample that functions properly when given the right class structure as shown below. Additionally, VisibilityonLegend will function flawlessly.
<chart:SfChart x:Name="Chart" Margin="10">
<chart:SfChart.Resources>
<local:VisibilityConverter x:Key="BoolToVisiblity"/>
</chart:SfChart.Resources>
. . .
<chart:FastLineBitmapSeries DataContext="{Binding AllSeries[Series1]}"
ItemsSource="{Binding ChartData}" Label="series1"
VisibilityOnLegend="{Binding AllSeriesVisibility[Series1],
Converter={StaticResource BoolToVisiblity}}"
XBindingPath="XValue" YBindingPath="YValue1" />
<chart:FastLineBitmapSeries DataContext="{Binding AllSeries[Series2]}"
ItemsSource="{Binding ChartData}" Label="series2"
VisibilityOnLegend="{Binding AllSeriesVisibility[Series2],
Converter={StaticResource BoolToVisiblity }}"
XBindingPath="XValue" YBindingPath="YValue2" />
. . .
</chart:SfChart>
public class ViewModel
{
public Dictionary<string, ViewModel1> AllSeries { get; set; } =
new Dictionary<string, ViewModel1>();
public string Series1Name { get; set; } = "Series1";
public string Series2Name { get; set; } = "Series2";
public ViewModel()
{
AllSeries["Series1"] = new ViewModel1(false);
AllSeries["Series2"] = new ViewModel1(true);
}
}
public class ViewModel1
{
private ObservableCollection<DataPoint> _chartData;
public ObservableCollection<DataPoint> ChartData
{
get { return _chartData; }
set { _chartData = value; }
}
public Dictionary<string, bool> AllSeriesVisibility { get; set; } = new Dictionary<string, bool>();
public ViewModel1(bool value)
{
AllSeriesVisibility["Series1"] = value;
AllSeriesVisibility["Series2"] = value;
var vTemp = new ObservableCollection<DataPoint>();
var random = new Random();
for (var i = 1; i < 15; i++)
{
vTemp.Add(new DataPoint { XValue = i, YValue1 = random.NextDouble(),
YValue2=random.NextDouble() });
}
ChartData = vTemp;
}
}
Please check this and let us know if you need any further assistance.
Regards,
Muneesh Kumar G

WPF MVVM: Filter by member displayed in the listview

I have gridview within a listview. There is a column, "Department" that is bound to a property "Department" in the model and also it has associated a conveter.
Converter takes the value that comes from the property and displays it in another form (with another string).
For example, if this property "Department" has a value of "100AB" in the column is displayed as "Financial", if value comes to "200CB" in the column is displayed "Administration" and so on...
My problem is when filtering listview using a filter. Internally it filter by "100AB", "200CB" instead of the value displayed "Financial" and "Administration", so how to solve this?
View (xaml):
<ListView Grid.Row="1" Grid.Column="0"
Name="MyListView"
ItemsSource="{Binding Path=View}"
<GridViewColumn Header="Department" Width="190"
DisplayMemberBinding="{Binding Department, Converter={StaticResource DeptTypeConverter}}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Right"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Converter:
public class DeptTypeConverter: IValueConverter
{
#region Constants
private const string DeptFinancialType = "100AB";
private const string DeptAdminType = "200CB";
private const string DeptFinancialView = "Finanacial";
private const string DeptAdminView = "Administration";
#endregion
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Do the conversion from drink type to present it in the view
string s = (string)value;
if (s == DeptFinancialType )
return DeptFinancialView;
else if (s == DeptAdminType)
return DeptAdminView;
else
throw new Exception(string.Format("Cannot convert, unknown value {0}", value));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Do the conversion from presentation to data type
string s = (string)value;
if (s.Equals(DeptFinancialView, StringComparison.InvariantCultureIgnoreCase))
return DeptFinancialType;
else if (s.Equals(DeptAdminView, StringComparison.InvariantCultureIgnoreCase))
return DeptAdminType;
else
throw new Exception(string.Format("Cannot convert, unknown value {0}", value));
}
}
Filter in view model:
private CollectionView view;
public CollectionView View
{
get
{
return this.view;
}
private set
{
if (this.view == value)
{
return;
}
this.view = value;
OnPropertyChanged("View");
}
}
// This code in constructor
this.View = (CollectionView)CollectionViewSource.GetDefaultView(this.MyListView);
this.View.Filter = UserFilter;
//
private bool MyFilter(object item)
{
if (String.IsNullOrEmpty(this.TextToFilter))
{
return true;
}
else
{
DataModel m = (item as DataModel);
bool result = (m.Department.IndexOf(this.TextToFilter, StringComparison.OrdinalIgnoreCase) >= 0);
return result;
}
}
I have other fields in the filter which I filter by but for simplicity I have not specified within MyFilter method. This fields are not using a converter, it is not necessary in this case, only is necessary in the case I have provided.
DataModel is the data model and contains "Department" property which view is bound to.
this.TextToFilter is a textbox in the view to filter by.
ATTEMPT #1:
Instead of using ConvertBack in DeptTypeConverter I have used Convert (no need to modify anything within Convert method). Below is working correctly.
private bool MyFilter(object item)
{
if (String.IsNullOrEmpty(this.TextToFilter))
{
return true;
}
else
{
DataModel m = (item as DataModel);
bool result = (new Converters.DeptTypeConverter().Convert(m.Department, null, null, null).ToString().IndexOf(this.TextToFilter, StringComparison.OrdinalIgnoreCase) >= 0);
return result;
}
}
m.Department contains the internal stored value (not the displayed one).
I think its better to use Convert rather than ConvertBack as user types the displayed text (no the value stored internally) when searching. Using ConvertBack requires more logic to implement and it is not as easy as using simply Convert.
If someone has any other better idea, please share. Any idea or improvements are always welcome. As far as possible I would like to not break the MVVM pattern architecture.
I do feel the best way to do this would be to not use an IValueConverter at all. I would change your DataModel class to add a new DepartmentDisplay property. Use the DepartmentDisplay property for the GridViewColumn binding and for filtering, and Department for whatever you do with the data after the grid is displayed. This would be the simplest and most MVVM solution, it removes the IValueConverter entirely.
DataModel....
public string Department { get; set; }
public string DepartmentDisplay
{
get
{
if (Department == "100AB")
return "Financial";
if (Department == "200CB")
return "Administration";
return "";
}
}
View...
<GridViewColumn Header="Department" Width="190"
DisplayMemberBinding="{Binding DepartmentDisplay}">
ViewModel...
private bool MyFilter(object item)
{
if (String.IsNullOrEmpty(this.TextToFilter))
{
return true;
}
else
{
DataModel m = (item as DataModel);
bool result = (m.DepartmentDisplay.IndexOf(this.TextToFilter, StringComparison.OrdinalIgnoreCase) >= 0);
return result;
}
}

How to use FileSystemWatcher to refresh text being returned from converter

I have built a converter class where you pass in a file path and it returns the actual text of the file.
public class GetNotesFileFromPathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var txtFilePath = (string)value;
FileInfo txtFile = new FileInfo(txtFilePath);
if (txtFile.Exists == false)
{
return String.Format(#"File not found");
}
try
{
return File.ReadAllText(txtFilePath);
}
catch (Exception ex){
return String.Format("Error: " + ex.ToString());
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
The converter is applied like so in the XAML:
<TextBox x:Name="FilePath_Txt" >
<TextBox.Text>
<![CDATA[
\\igtm.com\ART\GRAPHICS\TST\820777\0010187775\69352C5D5C5D195.txt
]]>
</TextBox.Text>
</TextBox>
<TextBox x:Name="FilePathRead_Txt" Text="{Binding ElementName=FilePath_Txt,Path=Text,Converter={StaticResource GetNotesFileFromPathConverter},Mode=OneWay}" />
This is all working fine. However, if the text in the text file is updated, it is not reflected in the XAML. I've seen information on using the FileSystemWatcher, but am not sure how to apply it inside of a converter so that the text being returned is updated. can anyone help?
I wouldn't use a converter in this case since you'll need to setup a FileSystemWatcher on the file. I would bind the Text of FilePath_Txt to a property in your view model and bind the Text of FilePathRead_Txt to another property. You would then update the FileSystemWatcher to look for updates to this new file. If the filename changes or the file is updated then you would use the logic you had in your converter to update the FilePathRead_Txt property. If you aren't familiar with the MVVM pattern, take a look at this MSDN article.
In your view model:
string filename;
public string Filename
{
get {return filename;}
set {
if (filename != value)
{
filename = value;
OnNotifyPropertyChanged("Filename");
WatchFile();
UpdateFileText();
}
}
string fileText;
public string FileText
{
get {return fileText;}
set {
fileText = value;
OnNotifyPropertyChanged("FileText");
}
}
private void WatchFile()
{
// Create FileSystemWatcher on filename
// Call UpdateFileText when file is changed
}
private void UpdateFileText()
{
// Code from your converter
// Set FileText
}
In XAML:
<TextBox x:Name="FilePath_Txt" Text="{Binding Filename, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="FilePathRead_Txt" Text="{Binding FileText}" />

Windows Phone 7 ListPicker InvalidCastException

I have a problem building a simple crud form in WP7. I have spent a lot of time to display an Enum into a listpicker an now I see InvalidCastException when trying to bind to the (IsolatedStorage) object.
public class Bath {
public string Colour { get; set; }
public WaterType WaterType { get; set; }
}
public enum WaterType {
Hot,
Cold
}
The enum is bound to a ListPicker, but as there is not enum.GetValues() in WP7 this is not a simple task.
I have a simple type class...
public class TypeList
{
public string Name { get; set; }
}
And in my viewmodel, I have ObservableCollection and mock the values from the enum...
private ObservableCollection<TypeList> _WaterTypeList;
public ObservableCollection<TypeList> WaterTypeList
{
get { return _WaterTypeList; }
set
{
_WaterTypeList= value;
NotifyPropertyChanged("WaterTypeList");
}
}
public void LoadCollectionsFromDatabase()
{
ObservableCollection<TypeList> wTypeList = new ObservableCollection<WaterTypeList>();
wTypeList.Add(new TypeList{ Name = WaterType.Hot.ToString() });
wTypeList.Add(new TypeList{ Name = WaterType.Income.ToString() });
WaterTypeList = new ObservableCollection<TypeList>(wTypeList);
}
Finally, my xaml contains the listbox...
<toolkit:ListPicker
x:Name="BathTypeListPicker"
ItemsSource="{Binding WaterTypeList}"
DisplayMemberPath="Name">
</toolkit:ListPicker>
Im not sure if the above is best practise and indeed if the above is part of the problem but the above does give me a populated ListPicker.
Finally, when the form is submitted the cast causes a InvalidCastException.
private void SaveAppBarButton_Click(object sender, EventArgs e)
{
var xyz = WaterTypeList.SelectedItem; // type AppName.Model.typeList
Bath b = new Bath
{
Colour = ColourTextBox.Text ?? "Black",
WaterType = (WaterType)WaterTypeListPicker.SelectedItem
};
App.ViewModel.EditBath(b);
NavigationService.Navigate(new Uri("/Somewhere.xaml", UriKind.Relative));
}
}
Has anyone faced a simlar problem and can offer advice. I see that my opions are to concentrate on casting something meaningful from the ListPicker or should I rethink the way that the ListPicker is populated?
As far as I can see, WaterTypeList is an ObservableCollection that is a Type of and an observable collection doesn't have a SelectedItem property.
Your Bath class has a WaterType that accepts WaterType property and you are trying to cast a WaterTypeListPicker.SelectedItem to it.. so I'm assuming your WatertypeListPicker is your ListBox?
If it is, then you are doing it wrong because your ListBox's itemssource is bound to a class and you are trying to add a to your WaterType Property.
What I would do is say,
Bath b = new Bath
{
Colour = ColourTextBox.Text ?? "Black",
WaterType = WaterTypeListPicker.SelectedItem
};
Either change my property of Bath's WaterType to a TypeList so the above code would work. But I won't recommend doing another class to wrap the enum just to show it to the listbox.
What I would do is create an EnumHelper
public static class EnumExtensions
{
public static T[] GetEnumValues<T>()
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("Type '" + type.Name + "' is not an enum");
return (
from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select (T)field.GetValue(null)
).ToArray();
}
public static string[] GetEnumStrings<T>()
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("Type '" + type.Name + "' is not an enum");
return (
from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select field.Name
).ToArray();
}
}
And Bind it to a Collection
My ViewModel
public IEnumerable<string> Priority
{
get { return EnumExtensions.GetEnumValues<Priority>().Select(priority => priority.ToString()); }
public string SelectedPriority
{
get { return Model.Priority; }
set { Model.Priority = value; }
}
Like that.
My XAML.
<telerikInput:RadListPicker SelectedItem="{Binding SelectedPriority, Mode=TwoWay}" ItemsSource="{Binding Priority}" Grid.Column="1" Grid.Row="4"/>
The WaterTypeListPicker.SelectedItem is an object of type TypeList so it can't be cast to an object of type WaterType.
In order to convert back to a WaterType, you could replace your cast:
WaterType = (WaterType)WaterTypeListPicker.SelectedItem
with:
WaterType = (WaterType)Enum.Parse(
typeof(WaterType),
((TypeList)WaterTypeListPicker.SelectedItem).Name,
false)

WPF Databinding problem

I'm new to WPF and I have some difficulties when I'm trying to populate a ListView with a list of custom objects.
internal class ApplicationCode
{
public int Code { get; set; }
public IEnumerable<string> InstrumentCodes { get; set; }
}
I have a list of ApplicationCode which I set to ItemsSource to a ListView. I need to display the ApplicationCode.Code as a string and for the rest of the columns a check box which can be checked/unchecked depending if the column name is contained in the InstrumentCodes collection.
In order to set the check box I use a converter on databinding:
<DataTemplate x:Key="InstrumentCodeTemplate">
<CheckBox IsEnabled="False" IsChecked="{Binding Mode=OneTime, Converter={StaticResource InstrumentSelectionConverter}}" />
</DataTemplate>
The problem I have is because I can't know which is the current column at the time of cell data binding and I can't set the ConverterParameter.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ApplicationCode appCode = value as ApplicationCode;
return appCode != null && appCode.InstrumentCodes.Contains(parameter.ToString());
}
Small example:
Id | Code1 | Code3 | Code4
--------------------------------
123 | True | False | True
Data for row 1: ApplicationCode.InstrumentCodes {Code1, Code4}
There is a way to find out the column index or name? Or there is another way to solve this problem?
The column name should be nothing more then a visual; which means the needed data should all be residing in the underlying object model. Therefore each row of data is an object.
Perhaps a restructure of your code would suffice which would also remove the need for the converter...keep in mind this is an example to get the idea across and would need modified for actual use.
internal class ApplicationCode
{
private CodeService _codeService = new CodeService();
public int Code { get; set; }
public bool IsValidCode
{
get
{
return _codeService.DoesIntrumentCodeExist(Code.ToString());
}
}
}
internal class CodeService
{
private IEnumerable<string> _instrumentCodes;
public CodeService()
{
//instantiate this in another way perhaps via DI....
_instrumentCodes = new List<string>();
}
public bool DoesIntrumentCodeExist(String instrumentCode)
{
foreach (String code in _instrumentCodes)
{
if (code == instrumentCode)
return true;
}
return false;
}
}
The solution I got so far is to add the columns dynamically and to set the ConverterParameter on every column.
foreach (var instrument in instruments)
{
var column = new GridViewColumn
{
HeaderTemplate = GetColumnHeaderTemplate(instrument),
CellTemplate = GetColumnCellTemplate(instrument),
Header = instrument,
};
view.Columns.Add(column);
}
private static DataTemplate GetColumnCellTemplate(string instrument)
{
var binding = new Binding
{
ConverterParameter = instrument,
Converter = new InstrumentSelectionConverter(),
Mode = BindingMode.OneWay
};
var template = new DataTemplate();
template.VisualTree = new FrameworkElementFactory(typeof(CheckBox));
template.VisualTree.SetBinding(ToggleButton.IsCheckedProperty, binding);
return template;
}
I know this isn't the best solution and I would really appreciate if someone could show me a way to do this directly from .xaml.

Categories

Resources