This is my scenario: My DataTemplate of a ListView contains a TextBox and some buttons, one of the buttons is used to select and highlight all of the text in the TextBox. I can find many solutions for select and highlight text in TextBox from code behind, but none of them define the TextBox and the Button in DataTemplate. Anyone can help?
Thanks
You can do something like this below :
XAML :
<Window x:Class="SOWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView Width="200" Height="300" ItemsSource="{Binding FriendList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="100" Margin="2" Text="{Binding Name}"></TextBox>
<Button Content="Select" Click="Button_Click"></Button>
<Button Content="Delete"></Button>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Code Behind :
using System.Windows;
using System.Windows.Controls;
namespace SOWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var friendViewModel = new FriendViewModel();
friendViewModel.AddFriends();
this.DataContext = friendViewModel;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var parent = (StackPanel)((sender as Button).Parent);
var children = parent.Children;
foreach(var child in children)
{
if (child.GetType().Equals(typeof(TextBox)))
{
var tb = child as TextBox;
tb.Focus();
tb.SelectAll();
break;
}
}
}
}
}
ViewModel :
using System.Collections.ObjectModel;
namespace SOWPF
{
public class FriendViewModel
{
public ObservableCollection<Friend> FriendList
{ get; set; }
public void AddFriends()
{
FriendList = new ObservableCollection<Friend>();
FriendList.Add(new Friend() { Name = "Arpan" });
FriendList.Add(new Friend() { Name = "Nrup" });
FriendList.Add(new Friend() { Name = "Deba" });
}
}
public class Friend
{
public string Name { get; set; }
}
}
Probably would be a good using an Attached property set on the button, and in the attached code using a code something like written by cvraman.
Using this way you absolutely avoid the code behind structure, and better way to using mvvm
Related
My TextBox shows a property value of a class, which is changed based on the SelectedItem in ListBox. (So far, so good.) However, now I'd like to replace the value defined in Dictionary with a value which a user specified (The key is the SelectedItem in ListBox). This doesn't work, no matter what I do. It just throws an exception. Here is my full code:
MainWindow.xaml.cs
using ChangeTextBoxBasedOnListBox.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
public partial class MainWindow : Window
{
ObservableCollection<string> oc;
ObservableCollection<Graph> graph;
Dictionary<string, Graph> dic = new Dictionary<string, Graph>();
ListBox lB;
public MainWindow()
{
InitializeComponent();
oc = new ObservableCollection<string>()
{
"Test_1",
"Test_2"
};
graph = new ObservableCollection<Graph>()
{
new Graph(10),
new Graph(100)
};
listBox.ItemsSource = oc;
foreach (var test in oc.Select((k, i) => new { kvp = k, index = i }))
{
dic.Add(test.kvp, graph[test.index]);
}
}
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Graph dicValue = dic[(sender as ListBox).SelectedItem.ToString()];
textBox.Text = Convert.ToString(dicValue.Step);
}
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
// This works, but this isn't what I want to do
if (dic.ContainsKey("Test_1"))
dic["Test_1"].Step = 1000;
// What I want to do is:
// (dic[(The current SelectedItem in ListBox)].Step = (The value user specified)
// This doesn't work ... throws an exception
//if (lB.SelectedItem != null)
//{
// if (dic.ContainsKey(lB.SelectedItem.ToString()))
// {
// dic[lB.SelectedItem.ToString()].Step = (sender as Graph).Step;
// }
//}
}
}
}
MainWindow.xaml
<Window x:Class="ChangeTextBoxBasedOnListBox.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:ChangeTextBoxBasedOnListBox"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="238" Margin="88,82,0,0" VerticalAlignment="Top" Width="288" SelectionChanged="listBox_SelectionChanged"/>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="523,82,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" TextChanged="textBox_TextChanged"/>
</Grid>
</Window>
Model/Graph.cs
namespace ChangeTextBoxBasedOnListBox.Model
{
public class Graph
{
public Graph(int step) { Step = step; }
public int Step { get; set; }
}
}
... I think I just need one more step, but I cannot find the way. Please help me. Thank you in advance.
Your approach is far too complicated. Actually, you do not need any event handlers at all.
Simply pass the Dictionary directly to the ListBox's ItemsSource and set DisplayMemberPath and SelectedValuePath to its Key and Value properties. Thus the ListBox displays the key strings and you can directly access a Graph instance via the SelectedValue property of the ListBox.
<StackPanel>
<ListBox x:Name="listBox" DisplayMemberPath="Key" SelectedValuePath="Value"/>
<TextBox Text="{Binding SelectedValue.Step, ElementName=listBox}"/>
</StackPanel>
and everything works automatically with this code behind:
public MainWindow()
{
InitializeComponent();
listBox.ItemsSource = new Dictionary<string, Graph>()
{
{ "Test_1", new Graph(10) },
{ "Test_2", new Graph(100) }
};
}
Just when I thought I was getting better at this, TabControl is now giving me problems. I have read relevant posts here on StackOverflow, but have been unable to get my simple demo application to work the way I want it to.
To keep things focused, I'll start with a single question about something I don't understand.
I have a TabControl whose TabItems each host the same UserControl. When I set the TabControl.ContentTemplate's DataTemplate to my UserControl, a rendering of that control appears, but it looks like it's the same control for each tab. Or perhaps it's not tied to any of the tabs at all.
MainWindow.xaml
<Window x:Class="TabControlMvvm.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:localviews="clr-namespace:TabControlMvvm.Views"
Title="MainWindow" Height="350" Width="525">
<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding Selected}">
<TabControl.ContentTemplate>
<DataTemplate>
<localviews:PersonMainPanel />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
Code-behind just sets the ViewModel as its DataContext:
namespace TabControlMvvm {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow()
{
InitializeComponent();
DataContext = new TabControlMvvm.ViewModels.MainViewModel();
}
}
}
The TabItem's Content should be another UserControl, PersonMainPanel.xaml:
<UserControl x:Class="TabControlMvvm.Views.PersonMainPanel"
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:localviews="clr-namespace:TabControlMvvm.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Border BorderBrush="Red" BorderThickness="2">
<TabControl TabStripPlacement="Bottom">
<TabItem Header="Tab 1">
<localviews:MyTabItem />
</TabItem>
<TabItem Header="Tab 2">
<TextBlock Text="This was left blank intentionally" />
</TabItem>
<TabItem Header="Tab 3">
<TextBlock Text="This was also left blank intentionally" />
</TabItem>
</TabControl>
</Border>
</UserControl>
Code-behind:
namespace TabControlMvvm.Views {
/// <summary>
/// Interaction logic for PersonMainPanel.xaml
/// </summary>
public partial class PersonMainPanel : UserControl {
public PersonMainPanel()
{
InitializeComponent();
}
}
}
And the MainViewModel:
namespace TabControlMvvm.ViewModels {
public class MainViewModel : ViewModelBase {
public ICollectionView Tabs { get; set; }
public int Selected { get; set; }
public class Person
{
public string Name { get; set; }
}
public class DummyController {
public List<Person> Persons { get; private set; }
public DummyController()
{
Persons = new List<Person> {
new Person { Name = "Larry" },
new Person { Name = "Darryl" },
new Person { Name = "Other brother Darryl" }
};
}
}
public DummyController Controller { get; private set; }
public RelayCommand HelloCommand { get; set; }
public MainViewModel()
{
Controller = new DummyController();
/*
IEnumerable<TabItem> tabs = Enumerable.Range( 1, _controller.Persons.Count())
.Select( x => new TabItem { Header = String.Format( "Person {0}", x),
Content = new PersonMainPanel() });
*/
IEnumerable<TabItem> tabs = Enumerable.Range( 1, Controller.Persons.Count())
.Select( x => new TabItem { Header = String.Format( "Person {0}", x)});
Tabs = CollectionViewSource.GetDefaultView( tabs.ToList());
Tabs.MoveCurrentToFirst();
InitializeCommands();
}
private void InitializeCommands()
{
HelloCommand = new RelayCommand( () => { MessageBox.Show( String.Format( "Hello, Person {0} named {1}!",
Selected, Controller.Persons[Selected].Name)); });
}
}
}
PersonMainPanel hosts another TabControl, where Tab 1's Content is MyTabItem.xaml:
<UserControl x:Class="TabControlMvvm.Views.MyTabItem"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" />
<TextBox Text="{Binding Name}" Width="100" />
</StackPanel>
<Button Command="{Binding HelloCommand}" Content="Say Hello" />
</StackPanel>
</UserControl>
Code-behind:
namespace TabControlMvvm.Views {
/// <summary>
/// Interaction logic for MyTabItem.xaml
/// </summary>
public partial class MyTabItem : UserControl {
public MyTabItem()
{
InitializeComponent();
}
}
}
Which looks like this at runtime:
Issues I have so far:
When I enter Person 1's Name and then click the Person 2 tab, Person 1's Name is still visible, hence my assumption that the controls are not databound properly. I understand that ItemsControls do not pass their DataContext down to their children, but I am not sure how to fix this without associating the View in code-behind.
I would have expected to get databinding errors in the Output window because of the missing DataContext, but I don't get any errors. I assume the DataContext is null, but wouldn't this still result in a binding error?
How can I use Snoop effectively to debug problems like this?
Here's the sample solution: http://www.filedropper.com/tabcontrolmvvm
Here is solution:
In MainWindow modify your TabControl template, to bind Header from your Model:
<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding Selected}">
<TabControl.ContentTemplate>
<DataTemplate>
<localviews:PersonMainPanel />
</DataTemplate>
</TabControl.ContentTemplate>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
In MyTabItem.xaml, set UpdateTrigger, because default one 'OnLostFocus' can sometimes not save your data:
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Width="100" />
In MainViewModel modify creating of your tabs, so it will have Name property too:
IEnumerable<TabItem> tabs = Enumerable.Range( 1, Controller.Persons.Count())
.Select( x => new TabItem { Header = String.Format("Person {0}", x), Name = Controller.Persons[x-1].Name });
Also, the most important, create own TabItem class to contain some bounded data:
public class TabItem
{
public string Name { set; get; }
public string Header { set; get; }
}
This is a very basic question, and I'm certain the reason I haven't found an answer is because I'm not 100% positive how to google it.
I have a very simple project, where I want to use a class that contains my info.
public class MyInfo
{
public string name = String.Empty;
public string ssn = String.Empty;
public string dob = String.Empty;
}
very basic.
I have a xaml file with buttons, and I just want to set the value of the variables in my class, to the contents in my buttons. Here's the xaml.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Name="name" Content="John Doe" HorizontalAlignment="Left" Margin="117,60,0,0" VerticalAlignment="Top" Width="75" Click="name_click"/>
<Button Name="ssn" Content="222-22-2222" HorizontalAlignment="Left" Margin="117,120,0,0" VerticalAlignment="Top" Width="75" Click="ssn_click"/>
<Button Name="dob" Content="June 1st 1992" HorizontalAlignment="Left" Margin="117,178,0,0" VerticalAlignment="Top" Width="75" Click="dob_click"/>
</Grid>
</Window>
The problem I'm having, is that the only way I know how to do this (being a total C# noob) is by having my class initialization in a super wide scope.
For example, here's my cs file with comments on what I initially did, but not what I think should be done.
MainWindow.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 WpfApplication1
{
public class MyInfo
{
public string name = String.Empty;
public string ssn = String.Empty;
public string dob = String.Empty;
}
// If i create a class instance here like this
//MyInfo infoTest = new MyInfo();
// then I can just set the values in the click functions like
//infoTest.dob = dob.Content.ToString();
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void name_click(object sender, RoutedEventArgs e)
{
//save name.content into MyInfo.name
}
private void ssn_click(object sender, RoutedEventArgs e)
{
//save ssn.content into MyInfo.ssn
}
private void dob_click(object sender, RoutedEventArgs e)
{
//save dob.Content into MyInfo.dob
}
}
}
I would think it would be better to create an instance of my class in the MainWindow class, after InitializeComponent();, but then I'm not certain how to get my values into the class object with a closed scope.
Just like this also you should use Auto-Implemented Properties instead of public fields:
public Window1()
{
InitializeComponent();
MyInfo myinfo = new MyInfo();
myinfo.Name = name.Content.ToString();
myinfo.Ssn = ssn.Content.ToString();
myinfo.Dob = dob.Content.ToString();
}
public class MyInfo
{
public string Name { get; set; }
public string Ssn { get; set; }
public string Dob { get; set; }
}
If you want to set properties after click buttons you should try this:
MyInfo myinfo = new MyInfo();
public Window1()
{
InitializeComponent();
}
Then:
private void name_Click(object sender, RoutedEventArgs e)
{
myinfo.Name = name.Content.ToString();
}
Another method of achieving this would be to make use of Binding.
public class MyInfo
{
public string Name { get; set; }
public string Ssn { get; set; }
public string Dob { get; set; }
}
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyInfo();
}
...
And your XAML will look like this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Name="name" Content="{Binding Name}" HorizontalAlignment="Left" Margin="117,60,0,0" VerticalAlignment="Top" Width="75"/>
<Button Name="ssn" Content="{Binding Ssn}" HorizontalAlignment="Left" Margin="117,120,0,0" VerticalAlignment="Top" Width="75"/>
<Button Name="dob" Content="{Binding Dob}" HorizontalAlignment="Left" Margin="117,178,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
This will allow you to avoid having to use Click events to set the properties of your object. You can find an excellent tutorial here.
The answer is already been marked, but I'd like to give you another POV using binding. Which i prefer to separate GUI/Business layer.
Some code:
public partial class MainWindow : Window
{
public class MyInfo
{
public string Name { get; set; }
public string Ssn { get; set; }
public string Dob { get; set; }
}
private MyInfo _myInfo;
public MainWindow()
{
InitializeComponent();
_myInfo = new MyInfo();
_myInfo.Name = "My name";
this.DataContext = _myInfo;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("My name is '" + _myInfo.Name + "'");
}
}
XAML
<Window x:Class="BindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Width="200" VerticalAlignment="Center">
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Ssn}" />
<TextBox Text="{Binding Dob}" />
<Button Content="Click me" Click="Button_Click" />
</StackPanel>
</Window>
It's even possible to update the TextBoxes from code (without writing directly to the Text property), assigning your class. Using the INotifyPropertyChanged
I have a program that searches a directory for files matching certain criteria. This search process takes a long time, so I have to call it asynchronously. When the search algorithm finds a file, it triggers an event. My MainWindow instance listens for this event and needs to update the GUI. How can I bind these "added" files to a ListView? I figured that I could use an ObservableCollection<FileInfo> instance, but I can't figure out how to bind it.
I've stripped out all of the irrelevant controls and code. Here are the two relevant files.
MainWindow.xaml:
<Window x:Class="Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CR Search" Height="395" Width="525">
<Grid>
<ListView x:Name="Results">
<ListView.View>
<GridView>
<GridViewColumn Header="Filename"/>
<GridViewColumn Header="Directory"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.IO;
using System.Threading.Tasks;
public partial class MainWindow
{
private SearchLogic _backgroundSearch;
private async void Search(object sender, RoutedEventArgs e)
{
// TODO: clear Results
_backgroundSearch = new SearchLogic("", new DirectoryInfo("C:\"));
_backgroundSearch.FileAdded += FileAdded;
await Task.Run(new Action(_backgroundSearch.Search));
}
private void FileAdded(object sender, FileAddedEventArgs eventArgs)
{
// TODO: add eventArgs.File to Results
// eventArgs.File is an instance of FileInfo
}
}
Here is a simple example
Your XAML
<Window x:Class="WpfApplication10.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350"
Loaded="Window_Loaded">
<Grid>
<ListBox ItemsSource="{Binding FileNames}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label>Name</Label>
<TextBlock Text="{Binding Name}"/>
<Label>Modified</Label>
<TextBlock Text="{Binding LastModified}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Your Code Behind
public partial class MainWindow : Window
{
public class FileInfo
{
public string Name { get; set; }
public DateTime LastModified { get; set; }
public FileInfo(string name)
{
Name = name;
LastModified = DateTime.Now;
}
}
ObservableCollection<FileInfo> mFileNames = new ObservableCollection<FileInfo>();
public ObservableCollection<FileInfo> FileNames
{
get
{
return mFileNames;
}
}
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((x) =>
{
while (true)
{
Dispatcher.BeginInvoke((Action)(() =>
{
mFileNames.Add(new FileInfo("X"));
}));
Thread.Sleep(500);
}
});
}
}
If you run this problem you will notice that the listbox updates every half a second with a new item. Basically the key thing to note is that the ObservableCollection can only be updated from the UI thread so if you refactor the above code you need need to somehow use the Dispatcher of the current UI thread to update it
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));
}
}
}
}