Binding to User Control Properties in an Items Control - c#

Can someone tell me why the way I am binding data here does not work? I was able to do this fine with using a GridView. I am not sure why the data is not being passed to the user control here, in addition it compiles fine and shows the user controls with there default text
Main.xaml.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace ItemsControlSample
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
PopulateData();
}
public class someKindaOfDataHolder
{
public string Text1;
public string Text2;
}
private void PopulateData()
{
List<someKindaOfDataHolder> dataAndStuff = new List<someKindaOfDataHolder>();
for (int i = 0; i < 5; ++i)
{
dataAndStuff.Add(new someKindaOfDataHolder()
{
Text1 = "data spot 1: " + i.ToString(),
Text2 = "data spot 2: " + (i + 2).ToString()
});
}
ListOfAUserControls.ItemsSource = dataAndStuff;
}
}
}
Main.xaml
<Page
x:Class="ItemsControlSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ItemsControlSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer>
<ItemsControl x:Name="ListOfAUserControls" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CustomUserControl DynamicText1Text="{Binding Text1}" DynamicText2Text="{Binding Text2}" Margin="0,0,10,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="100,46,-50,0"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
</Page>
CustomUserControl.xaml.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
namespace ItemsControlSample
{
public sealed partial class CustomUserControl : UserControl
{
public static readonly DependencyProperty DynamicText1Property =
DependencyProperty.Register("DynamicText1Text", typeof(string), typeof(CustomUserControl), new PropertyMetadata(null, OnDynamicText1PropertyChanged));
public string DynamicText1Text
{
get { return (string)GetValue(DynamicText1Property); }
set { SetValue(DynamicText1Property, value); }
}
public static readonly DependencyProperty DynamicText2Property =
DependencyProperty.Register("DynamicText2Text", typeof(string), typeof(CustomUserControl), new PropertyMetadata(null, OnDynamicText2PropertyChanged));
public string DynamicText2Text
{
get { return (string)GetValue(DynamicText2Property); }
set { SetValue(DynamicText2Property, value); }
}
public CustomUserControl()
{
this.InitializeComponent();
}
private static void OnDynamicText1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = d as CustomUserControl;
obj.DynamicText1.Text = e.NewValue.ToString();
}
private static void OnDynamicText2PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var obj = d as CustomUserControl;
obj.DynamicText2.Text = e.NewValue.ToString();
}
}
}
CustomUserControl.xaml:
<UserControl
x:Class="ItemsControlSample.CustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ItemsControlSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="800"
d:DesignWidth="800">
<Grid Background="Blue">
<Grid.RowDefinitions>
<RowDefinition Height="6*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Image Source="ms-appx:///Assets/MSIcon.png" />
<StackPanel Grid.Row="1" Margin="25">
<TextBlock Text="Obay" FontSize="45" />
<TextBlock x:Name="DynamicText1" Text="DynamicText1" FontSize="35" />
<TextBlock x:Name="DynamicText2" Text="DynamicText2" FontSize="35" />
</StackPanel>
</Grid>
</UserControl>
Thanks!

You need to set the DataContext somewhere. Without it - your bindings have no context and they fail (look at the Output window in VS when debugging Debug builds to see binding errors). You are setting ItemsSource="{Binding}" where the binding has no context.
Then again - you are overriding the ItemsSource elsewhere with your "ListOfAUserControls.ItemsSource = dataAndStuff;" call, so that is likely not the issue causing your problem in the end. The DataContext of an item in an ItemsControl should be set automatically to an item in the ItemsSource collection.
Another problem that might block you there is that someKindaOfDataHolder.Text1 in your case is a field and it should be a property to work with bindings - try this instead:
public string Text1 { get; set; }

Related

How to change field to original value using a "reset" button in wpf

I have a class that has several properties, one of which is editable, another of which is calculated based on the editable value. I want to initialize the editable value with something and allow the user to change it however they wish. However, I also want to have a reset button that puts the original value back into the textbox. I have a third variable that stores the value of the original number. However, I am not sure how I am supposed to access the object when the reset button is clicked to put the value back into the textbox. I've put the relevant code below (if I shouldn't be posting everything please let me know, still new to stackoverflow how-to):
Main Window
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using HDR_BED_Calc_local.Testers;
using HDR_BED_Calc_local.Helpers;
namespace HDR_BED_Calc_local
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//var window = new MainWindow();
this.DataContext = new fraction_doses(800, 700, 900, 800, 900, 1, 3);
}
}
}
XAML
<Window x:Class="HDR_BED_Calc_local.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HDR_BED_Calc_local"
xmlns:uctesters="clr-namespace:HDR_BED_Calc_local.Testers"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<uctesters:fx_tester x:Name="fxtester_UC"/>
</Grid>
</Window>
Custom user control
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using HDR_BED_Calc_local.Helpers;
namespace HDR_BED_Calc_local.Testers
{
/// <summary>
/// Interaction logic for fx_tester.xaml
/// </summary>
public partial class fx_tester : UserControl
{
public fx_tester()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// What do I put here??
}
}
}
XAML
<UserControl x:Class="HDR_BED_Calc_local.Testers.fx_tester"
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:HDR_BED_Calc_local.Testers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="White">
<StackPanel HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">Fraction: </TextBlock>
<TextBlock Text="{Binding Path=fraction_number}"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">Current Dose: </TextBlock>
<TextBox x:Name="curr_fx_tb" Text="{Binding Path=editable_fraction_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">EQD2: </TextBlock>
<TextBlock Text="{Binding Path=this_fx_brachy_EQD2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
<Button Content="Reset" Click="Button_Click"/>
</StackPanel>
</UserControl>
Helper function with class
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace HDR_BED_Calc_local.Helpers
{
internal class fraction_doses : INotifyPropertyChanged
{
public int fraction_number { get; set; }
public double alpha_beta { get; }
private double _editable_fraction_dose;
public double editable_fraction_dose
{
get { return _editable_fraction_dose; }
set
{
_editable_fraction_dose = value;
calc_EQD2();
this.OnPropertyChanged("editable_fraction_dose");
}
}
public double actual_fraction_dose { get; }
public double pear_plan_dose { get; }
public double IMRT_plan_dose { get; }
public double max_dose_limit { get; }
public double preferred_dose_limit { get; }
private double _this_fx_brachy_EQD2;
public double this_fx_brachy_EQD2
{
get { return this._this_fx_brachy_EQD2; }
set
{
this._this_fx_brachy_EQD2 = value;
this.OnPropertyChanged("this_fx_brachy_EQD2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public fraction_doses(double current_dose, double pear_dose, double IMRT_dose, double max_dose_limit, double preferred_dose_limit, int fraction_number, int alpha_beta)
{
this.alpha_beta = alpha_beta;
this.actual_fraction_dose = current_dose;
this.editable_fraction_dose = current_dose;
this.pear_plan_dose = pear_dose;
this.IMRT_plan_dose = IMRT_dose;
this.max_dose_limit = max_dose_limit;
this.preferred_dose_limit = preferred_dose_limit;
this.fraction_number = fraction_number;
}
public void calc_EQD2()
{
// EQD2 is always reported in Gray even though we will be reporting cGy
double dose_Gy = this.editable_fraction_dose/100;
this.this_fx_brachy_EQD2 = Math.Round(1 * dose_Gy * (1+ dose_Gy / alpha_beta)/(1+2/alpha_beta), 2);
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You can try the following:
private void Button_Click(object sender, RoutedEventArgs e)
{
// What do I put here??
var dc = (fraction_doses ) this.DataContext:
if(dc!=null)
dc.Clear();
}
in your fraction_doses class add the method that clears the properties
public void Clear(){
this.MyProperty = MY_DEFAULT_VALUE;
//clear other properties..
}

WPF databinding of ICommand "freezes" after multiple Button clicks

This is my first time trying to databind an ICommand. I have a digital LED control that I would like to act like a Button, so I changed the DataTemplate for a Button control to look like an LED:
LED.xaml
<UserControl x:Class="LedControlDatabindingTest.LED"
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"
x:Name="root"
mc:Ignorable="d"
Height="Auto" Width="Auto">
<Grid DataContext="{Binding ElementName=root}">
<StackPanel Orientation="{Binding LEDOrientation, FallbackValue=Vertical}">
<!-- LED portion -->
<Button BorderBrush="Transparent" Background="Transparent" Click="Button_Click">
<Button.ContentTemplate>
<DataTemplate>
<Grid>
<Ellipse Grid.Column="0" Margin="3" Height="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}"
Width="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}"
Fill="{Binding ElementName=root, Path=LEDColor, FallbackValue=Green}"
StrokeThickness="2" Stroke="DarkGray" HorizontalAlignment="Center" />
<Ellipse Grid.Column="0" Margin="3" Height="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}"
Width="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}" HorizontalAlignment="Center">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,1.0">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.4" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</DataTemplate>
</Button.ContentTemplate>
</Button>
<!-- label -->
<TextBlock Grid.Column="1" Margin="3" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding LEDLabel, FallbackValue=0}" />
</StackPanel>
</Grid>
</UserControl>
I want the host application to be able to databind to properties like size, color, and label of the LED. In addition, I want to be able to bind to a command handler.
LED.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace LedControlDatabindingTest {
/// <summary>
/// Interaction logic for LED.xaml
/// </summary>
public partial class LED : UserControl
{
public static DependencyProperty LEDColorProperty = DependencyProperty.Register( "LEDColor", typeof(Brush), typeof(LED));
public Brush LEDColor
{
get { return this.GetValue(LEDColorProperty) as Brush; }
set {
this.SetValue( LEDColorProperty, value);
}
}
public static DependencyProperty LEDSizeProperty = DependencyProperty.Register( "LEDSize", typeof(int), typeof(LED));
public int LEDSize
{
get { return (int)GetValue(LEDSizeProperty); }
set {
SetValue( LEDSizeProperty, value);
}
}
public static DependencyProperty LEDLabelProperty = DependencyProperty.Register( "LEDLabel", typeof(string), typeof(LED));
public string LEDLabel
{
get { return (string)GetValue(LEDLabelProperty); }
set {
SetValue( LEDLabelProperty, value);
}
}
public static DependencyProperty LEDOrientationProperty = DependencyProperty.Register( "LEDOrientation", typeof(Orientation), typeof(LED));
public Orientation LEDOrientation
{
get { return (Orientation)GetValue(LEDOrientationProperty); }
set {
SetValue( LEDOrientationProperty, value);
}
}
public static readonly DependencyProperty LEDClickedProperty = DependencyProperty.Register("LEDClicked", typeof(ICommand), typeof(LED), new PropertyMetadata(null));
public ICommand LEDClicked
{
get { return (ICommand)GetValue(LEDClickedProperty); }
set { SetValue( LEDClickedProperty, value); }
}
public LED()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
LEDClicked.Execute( null);
}
}
}
My test application is simple.
MainWindow.xaml:
<Window x:Class="LedControlDatabindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LedControlDatabindingTest"
Title="MainWindow" Height="70" Width="250">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Digital Inputs:" />
<ListBox ItemsSource="{Binding AvailableDigitalInputs}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<local:LED LEDLabel="{Binding Index}" LEDColor="{Binding Color}" LEDSize="12" LEDClicked="{Binding Clicked}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</StackPanel>
</Window>
There are so no-nos in my code-behind, like the DataContext for my application, but I think for the purposes of this demo it's okay for now.
MainWindow.xaml.cs:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace LedControlDatabindingTest {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private class DigitalInputData : ViewModelBase
{
private Brush _color;
public Brush Color
{
get { return _color; }
set {
_color = value;
RaisePropertyChanged();
}
}
public int Index { get; set; }
public ICommand Clicked { get; set; }
private bool _state;
public DigitalInputData( int index, Brush on_color)
{
Index = index;
Color = Brushes.LightGray;
Clicked = new RelayCommand( () => {
// get current state of this digital input and then toggle it
_state = !_state;
// read back and update here until I get threaded updates implemented
Color = _state ? on_color : Brushes.LightGray;
});
}
}
private List<DigitalInputData> _inputs = new List<DigitalInputData>();
public ICollectionView AvailableDigitalInputs { get; set; }
public MainWindow()
{
InitializeComponent();
// For this example only, set DataContext in this way
DataContext = this;
for( int i=0; i<4; i++) {
_inputs.Add( new DigitalInputData( i, Brushes.Green));
}
AvailableDigitalInputs = CollectionViewSource.GetDefaultView( _inputs);
}
}
}
When I run this application, everything renders properly and according to my databound properties. The click handler works as well, and toggles the state of the LED.
But when I click the LED button numerous times, at some point (maybe after 20 clicks or so), it stops calling my databound ICommand. Why?
I got lucky and figured out a solution to the "freezing" problem, although I do not understand the technical reasoning.
In my DigitalInputData constructor, I created the handler for the RelayCommand using a lambda function instead of passing a reference to a handler. Once I switched over to passing the handler to the RelayCommand constructor, it worked great.

Webview Navigation causes freezing on winrt (non x86)

When using webview.navigate(url), the entire app freezes up. It's noticeable on x86 chips, but it completely freezes up tablets for close to 50 seconds.
I've tried many many things to try to marshall the thread, but absolutely nothing makes it better.
Any advice?
Here is the xaml and c#
<Page
x:Class="WebviewSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WebviewSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<ListView x:Name="listView" ItemsSource="{Binding}" SelectionChanged="ListView_OnSelectionChanged">
</ListView>
</Grid>
<Grid Grid.Column="1">
<WebView x:Name="webView"></WebView>
</Grid>
</Grid>
</Page>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace WebviewSample
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var itemsList = new List<ListViewItem>();
for (var i = 0; i < 300; i++)
{
var listViewItem = new ListViewItem {Content = "Click Me!"};
itemsList.Add(listViewItem);
}
listView.DataContext = itemsList;
}
private void ListView_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
webView.Navigate(new Uri("http://online.wsj.com/article/SB10001424127887324299104578529112289298922"));
}
}
}

Dynamically set TextBlock's text binding

I am attempting to write a multilingual application in Silverlight 4.0 and I at the point where I can start replacing my static text with dynamic text from a SampleData xaml file. Here is what I have:
My Database
<SampleData:something xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.MyDatabase" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<SampleData:something.mysystemCollection>
<SampleData:mysystem ID="1" English="Menu" German="Menü" French="Menu" Spanish="Menú" Swedish="Meny" Italian="Menu" Dutch="Menu" />
</SampleData:something.mysystemCollection>
</SampleData:something>
My UserControl
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="Something.MyUC" d:DesignWidth="1000" d:DesignHeight="600">
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MyDatabase}}">
<Grid Height="50" Margin="8,20,8,0" VerticalAlignment="Top" d:DataContext="{Binding mysystemCollection[1]}" x:Name="gTitle">
<TextBlock x:Name="Title" Text="{Binding English}" TextWrapping="Wrap" Foreground="#FF00A33D" TextAlignment="Center" FontSize="22"/>
</Grid>
</Grid>
</UserControl>
As you can see, I have 7 languages that I want to deal with. Right now this loads the English version of my text just fine. I have spent the better part of today trying to figure out how to change the binding in my code to swap this out when I needed (lets say when I change the language via drop down).
It sounds like you're looking for code like this:
Title.SetBinding(TextProperty, new Binding { Path = new PropertyPath(language) });
All it does is create a new Binding for the language you requested and use it to replace the old binding for the Title's Text property.
You are going about this the wrong way. Best practice for localization in Silverlight is to use resource files holding the translated keywords. Here is some more info about this:
http://msdn.microsoft.com/en-us/library/cc838238%28VS.95%29.aspx
EDIT:
Here is an example where I use a helper class to hold the translated strings. These translations could then be loaded from just about anywhere. Static resource files, xml, database or whatever. I made this in a hurry, so it is not very stable. And it only switches between english and swedish.
XAML:
<UserControl x:Class="SilverlightApplication13.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SilverlightApplication13"
mc:Ignorable="d"
d:DesignWidth="640"
d:DesignHeight="480">
<UserControl.Resources>
<local:TranslationHelper x:Key="TranslationHelper"></local:TranslationHelper>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<StackPanel>
<TextBlock Margin="10"
Text="{Binding Home, Source={StaticResource TranslationHelper}}"></TextBlock>
<TextBlock Margin="10"
Text="{Binding Contact, Source={StaticResource TranslationHelper}}"></TextBlock>
<TextBlock Margin="10"
Text="{Binding Links, Source={StaticResource TranslationHelper}}"></TextBlock>
<Button Content="English"
HorizontalAlignment="Left"
Click="BtnEnglish_Click"
Margin="10"></Button>
<Button Content="Swedish"
HorizontalAlignment="Left"
Click="BtnSwedish_Click"
Margin="10"></Button>
</StackPanel>
</Grid>
</UserControl>
Code-behind + TranslationHelper class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.ComponentModel;
namespace SilverlightApplication13
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
//Default
(this.Resources["TranslationHelper"] as TranslationHelper).SetLanguage("en-US");
}
private void BtnEnglish_Click(object sender, RoutedEventArgs e)
{
(this.Resources["TranslationHelper"] as TranslationHelper).SetLanguage("en-US");
}
private void BtnSwedish_Click(object sender, RoutedEventArgs e)
{
(this.Resources["TranslationHelper"] as TranslationHelper).SetLanguage("sv-SE");
}
}
public class TranslationHelper : INotifyPropertyChanged
{
private string _Contact;
/// <summary>
/// Contact Property
/// </summary>
public string Contact
{
get { return _Contact; }
set
{
_Contact = value;
OnPropertyChanged("Contact");
}
}
private string _Links;
/// <summary>
/// Links Property
/// </summary>
public string Links
{
get { return _Links; }
set
{
_Links = value;
OnPropertyChanged("Links");
}
}
private string _Home;
/// <summary>
/// Home Property
/// </summary>
public string Home
{
get { return _Home; }
set
{
_Home = value;
OnPropertyChanged("Home");
}
}
public TranslationHelper()
{
//Default
SetLanguage("en-US");
}
public void SetLanguage(string cultureName)
{
//Hard coded values, need to be loaded from db or elsewhere
switch (cultureName)
{
case "sv-SE":
Contact = "Kontakt";
Links = "Länkar";
Home = "Hem";
break;
case "en-US":
Contact = "Contact";
Links = "Links";
Home = "Home";
break;
default:
break;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

Binding ListBox to List in Silverilght not working

All,
I have what i think is the simplest example possible of data binding in silverlight... but clearly even that is too complicated for me :)
The XAML:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<ListBox x:Name="rblSessions">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SessionTitle}" Foreground="Black" FontSize="30" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
List<Sessions> theSessions = makeSessions();
rblSessions.ItemsSource = theSessions;
rblSessions.DataContext = theSessions;
}
public List<Sessions> makeSessions()
{
List<Sessions> theReturn = new List<Sessions>();
for (int i = 0; i < 20; i++)
{
Sessions s = new Sessions() { SessionID = i, SessionTitle = string.Format("title{0}", i) };
theReturn.Add(s);
}
return theReturn;
}
}
public class Sessions
{
public int SessionID;
public string SessionTitle;
}
}
When I run the app, I get a listbox with 20 elements in it, but each element is empty, and only about 5 pixels tall (though I set FontSize to "30")
What am I doing wrong? Help please and thanks
/jonathan
You must make your Session class members into properties in order to use them in a binding. This should fix it:
public class Sessions
{
public int SessionID { get; set; }
public string SessionTitle { get; set; }
}

Categories