Create binding to string in Resources.resx from code behind - c#

I started by making a label in XAML with its content bound to a string in my resources file. I've implemented localization and confirm that when I change languages, the label's content updates accordingly.
Now I need to do the same from code behind.
Here is a taste of the XAML:
<Grid Background="#FF313131">
<ScrollViewer>
<StackPanel x:Name="GeneralTab_StackPanel">
<WrapPanel VerticalAlignment="Top" Background="{Binding AxisDataColorCode}" Margin="2,2,2,0">
<Label x:Name="lbl_General_MachineType" Content="{Binding GUI_MachineType, Source={StaticResource Resources}}" FontSize="20" />
<Label x:Name="lbl_General_MachineTypeResult" Content="{Binding MachineBaseType}" FontSize="20" />
</WrapPanel>
<WrapPanel....
Attempting to recreate this in code-behind I have the following:
Binding BgColorBinding = new Binding("AxisDataColorCode");
// Something needs to change here. I've tried a bunch of things already with no luck.
Binding GUI_MachineTypeBinding = new Binding("GUI_MachineType");
GUI_MachineTypeBinding.Source = Properties.Resources.GUI_MachineType;
Binding MachineBaseTypeBinding = new Binding("MachineBaseType");
Label Label_MachineType = new Label();
Label_MachineType.Name = "lbl_General_MachineType";
Label_MachineType.FontSize = 20;
// This does not work at all. Help!
Label_MachineType.SetBinding(Label.ContentProperty, GUI_MachineTypeBinding);
// this works! but it's not a binding and doesn't update...
// Label_MachineType.Content = Properties.Resources.GUI_MachineType;
Label Label_MachineTypeResult = new Label();
Label_MachineTypeResult.Name = "lbl_General_MachineTypeResult";
Label_MachineTypeResult.FontSize = 20;
Label_MachineTypeResult.SetBinding(Label.ContentProperty, MachineBaseTypeBinding);
WrapPanel MachineTypeWrapPanel = new WrapPanel();
MachineTypeWrapPanel.Name = "MachineTypeWrapPanel";
MachineTypeWrapPanel.VerticalAlignment = System.Windows.VerticalAlignment.Top;
MachineTypeWrapPanel.Margin = new Thickness(2, 2, 2, 0);
MachineTypeWrapPanel.SetBinding(WrapPanel.BackgroundProperty, BgColorBinding);
MachineTypeWrapPanel.Children.Add(Label_MachineType);
MachineTypeWrapPanel.Children.Add(Label_MachineTypeResult);
My other bindings work fine, because I've just tied them to properties in code behind that implement property changed notification.
Trying to bind to any of the keys in my resources however, gives me nothing. The label's content is simply blank, and there are no errors in my debug output window.
I can't find any examples of anyone binding to their Properties.Resources.Whatever from code behind anywhere.
The solution:
Thanks Henka!
Binding GUI_MachineTypeBinding = new Binding("GUI_MachineType");
GUI_MachineTypeBinding.Source = Application.Current.FindResource("Resources");
....
Label_MachineType.SetBinding(Label.ContentProperty, GUI_MachineTypeBinding);

If you set the Binding from code behind the UI will not be notified you should create your custom extension and save a WeakReference to the DependencyProperty and update the value when the culture changed, i propose an other solution to use, have a look at this article.Advanced WPF Localization

Related

How can I add a label in C# to a grid in my XAML code?

I have this template:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Japanese.Templates.PointReductionModeTemplate" x:Name="this">
<StackLayout BackgroundColor="#FFFFFF" Padding="20,0" HeightRequest="49" Margin="0">
<Grid VerticalOptions="CenterAndExpand" x:Name="ABC">
</Grid>
</StackLayout>
</ContentView>
How can I add this label to the Grid in C# with this Text and Style? Note that I want to be able to reference the Source={x:Reference this} also
<Label Text="{Binding Text, Source={x:Reference this}}" Style="{StaticResource LabelText}" />
You can use SetBinding() to create the binding while using parent (this) as binding-source. Explicitly specifying the source parameter tells the Binding to refer that instance as Source.
//<Label Text="{Binding Text, Source={x:Reference this}}" ...
var label = new Label();
label.SetBinding(Label.TextProperty, new Binding(nameof(Text), source: this));
Now setting the Style dynamically from resources is not as straightforward. When we use StaticResource extension in XAML, it takes care of walking up the visual-tree to find the matching resource (style). In code-behind, you will have to manually define the exact resource-dictionary, the style is defined in.
So assuming you have the 'LabelText' defined in App.xaml - you can use following code:
//... Style="{StaticResource LabelText}" />
//if the style has been defined in the App resources
var resourceKey = "LabelText";
// resource-dictionary that has the style
var resources = Application.Current.Resources;
if (resources.TryGetValue(resourceKey, out object resource))
label.Style = resource as Style;
If the style is defined in PointReductionModeTemplate.xaml (or ContentView resources), you can alternatively use:
var resources = this.Resources;
if (resources.TryGetValue(resourceKey, out object resource))
label.Style = resource as Style;
And finally add the label to grid.
this.ABC.Children.Add(label);
you should make an object of label class then add this object to the Chidlers property of your grid.
Label dynamicLabel = new Label();
dynamicLabel.Name = "NewLabel";
dynamicLabel.Content = "TEST";
dynamicLabel.Width = 240;
dynamicLabel.Height = 30;
dynamicLabel.Margin = new Thickness(0, 21, 0, 0);
dynamicLabel.Foreground = new SolidColorBrush(Colors.White);
dynamicLabel.Background = new SolidColorBrush(Colors.Black);
Grid.SetRow(dynamicLabel, 1);
Grid.SetColumn(dynamicLabel, 0);
gride.Children.Add(dynamicLabel);
You can try this
Grid grid = new Grid();
grid.SetBinding(Grid.BindingContextProperty, "Source");
Label label = new Label();
label.SetBinding(Label.TextProperty,FieldName);
Resources.Add ("label", customButtonStyle);
grid.Children.Add(label)
To add Label in Grid give your preferred position. Just sample code to set bindings on Label programatcally
label.BindingContext = list; // The observablecollection
label.SetBinding(Label.TextProperty, "Count");
Styles programatically & Binding programatically
Hope it help you.

Changing from xaml design into C# coding

I am currently try to programatically get the ListBox
I tried to find many ways but, I can't make this works.
Here is the xaml part of code:
<ListBox Grid.Row="2" Grid.ColumnSpan="2" x:Name="PeerList" Margin="10,10,0,10">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" FontSize="{StaticResource PhoneFontSizeMedium}" Margin="40,0,0,0"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want this same operation to be done programatically.
Someone familiar to XAML to C# help me to solve this. .
It is something like this
ListBox listbox = new ListBox();
DataTemplate dataTemplate = new DataTemplate();
FrameworkElementFactory elementFactory = new FrameworkElementFactory(typeof(TextBlock));
elementFactory .SetBinding(TextBlock.TextProperty, new Binding("DisplayName"));
dataTemplate.VisualTree = elementFactory;
listbox.ItemTemplate = dataTemplate ;
If you want Programatically display the name of the peers in this list means follow #Hiệp Lê Answer.
Otherwise if you want only to get the name of the peers. Just follow this.
void SearchPeers()
{
List<string> name = new List<string>();
var peers = await PeerFinder.FindAllPeersAsync();
for(int i=0;i<peers.Count;i++)
{
string peerName = peers.DisplayName;
name.Add(peerName);
}
}
This will get you the name of the peers available.

How to make this code more efficient?

As i am not very advanced in C# yet, I try to learn how to make my code more efficient.
I stored a lot of strings in some of the properties.
At the start of the application, i load all the seperatie properties into the textboxes.
I now ise this code to load them all:
private void LoadStoredStrings()
{
txtT1S1.Text = Properties.Settings.Default.strT1L1;
txtT1S2.Text = Properties.Settings.Default.strT1L2;
txtT1S3.Text = Properties.Settings.Default.strT1L3;
txtT1S4.Text = Properties.Settings.Default.strT1L4;
txtT1S5.Text = Properties.Settings.Default.strT1L5;
txtT1S6.Text = Properties.Settings.Default.strT1L6;
txtT1S7.Text = Properties.Settings.Default.strT1L7;
txtT1S8.Text = Properties.Settings.Default.strT1L8;
txtT1S9.Text = Properties.Settings.Default.strT1L9;
txtT1S10.Text = Properties.Settings.Default.strT1L10;
}
Obvious i can see the logic that each stored propertie ending with T1L1 also fits to the txt that ends with T1S1.
I just know this should be done in a more elegant and solid way than what i did now.
Could anyone push me in the right direction?
you can bind your properties directly to your textboxes
<UserControl xmlns:Properties="clr-namespace:MyProjectNamespace.Properties" >
<TextBox Text="{Binding Source={x:Static Properties:Settings.Default}, Path=strT1L1, Mode=TwoWay}" />
If you can get all of those constants into a List<string>, you could use it to bind to an ItemsControl with TextBlock inside:
Code behind or View Model
private ObservableCollection<string> _defaultProperties = new ObservableCollection<string>();
public ObservableCollection<string> DefaultProperties
{
get { return _defaultProperties; }
}
XAML
<ListBox ItemsSource="{Binding Path=DefaultProperties"}>
<ListBox.ItemTemplate>
<DataTemplate>
<!--Just saying "Binding" allows binding directly to the current data context vs. a property on the data context-->
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Event Binding Using { } [duplicate]

This question already has answers here:
Assigning events in object initializer
(3 answers)
Closed 9 years ago.
I am creating a TextBox in code-behind.
TextBox textBox = new TextBox();
I also have a function:
private void TextBox_Focus(object sender, RoutedEventArgs e)
{
// does something
}
I want to bind TextBox_Focus to TextBox.GotFocus.
Rather than setting each property individually like so
TextBox textBox = new TextBox();
textBox.Width = 100;
textBox.Height = 25;
textBox.Background = Brushes.White;
textBox.Foreground = Brushes.Blue;
textBox.GotFocus += TextBox_Focus;
I prefer using braces (curly brackets) {}:
TextBox textBox = new TextBox()
{
Width = 100,
Height = 25,
Background = Brushes.White,
Foreground = Brushes.Blue
};
However, when I use the braces method, I am unable to bind to events.
I have tried doing the following, but to no avail...
TextBox textBox = new TextBox()
{
Width = 100,
Height = 25,
Background = Brushes.White,
Foreground = Brushes.Blue,
this.GotFocus += TextBox_Focus
};
Question:
Is there a way to event bind using the braces ({}) method?
Update:
The element is being created dynamically, so I cannot use XAML.
No. Object initializers only work to set properties or fields. You're trying to subscribe to an event, which isn't supported in Object initializer syntax.
As other commenters are saying, XAML is the best way to initialize WPF controls.
Apparently Mono though supports what you're asking for. See: Initializing events with initializer syntax
Why not use Xaml, you'll find it is quite flexible.
And also kinda WPF's thing.
<TextBox x:Name="textBox"
Width="100"
Height="25"
Background="White"
Foreground="Blue"
GotFocus="TextBox_Focus" />
As per your comment, you can do what you wish like so:
<ListBox ItemsSource="{Binding MyCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding }"
Width="100"
Height="25"
Background="White"
Foreground="Blue"
GotFocus="TextBox_Focus" />
</DataTemplate>
</ListBox.ItemTemplate>
If you make your Collection an ObservableCollection<T> when you add an item to the collection it will update your list box for you.
Try
EventManager.RegisterClassHandler(typeof(TextBox),TextBox.GotKeyboardFocusEvent, new RoutedEventHandler(yourMethod());

stackpanel in datapager silverlight

I am developing a silverlight navigation application and got stuck on the following problem...
The guy I am developing the app wants to have a News page where you can see all published news on the left side and the clicked (or latest news if none is clicked) on the right side. He wanted to have a header, text and publishing date for each news in the news list. Also he wanted to have paging so that there won't be to many news in the list at once...
I did this:
foreach (Model.News news in s)
{
StackPanel stackPanel = new StackPanel();
HyperlinkButton hyperlinkButton = new HyperlinkButton();
hyperlinkButton.Tag = news.Header;
hyperlinkButton.Content = news.Header;
hyperlinkButton.FontSize = 15;
hyperlinkButton.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
hyperlinkButton.Click += new RoutedEventHandler(Button_Click);
stackPanel.Children.Add(hyperlinkButton);
TextBlock textBlock = new TextBlock();
textBlock.Foreground = new SolidColorBrush(Colors.Gray);
textBlock.FontSize = 12;
textBlock.FontFamily = new FontFamily("Verdana");
textBlock.TextWrapping = TextWrapping.Wrap;
textBlock.Text = news.Text;
stackPanel.Children.Add(textBlock);
TextBlock dateTextBlock = new TextBlock();
dateTextBlock.Foreground = new SolidColorBrush(Colors.Gray);
dateTextBlock.FontSize = 10;
dateTextBlock.FontFamily = new FontFamily("Verdana");
dateTextBlock.TextWrapping = TextWrapping.Wrap;
dateTextBlock.FontWeight = FontWeights.Bold;
dateTextBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
dateTextBlock.Text = news.Date.ToShortDateString();
stackPanel.Children.Add(dateTextBlock);
stackPanel.Children.Add(new TextBlock());
newsStackPanel.Children.Add(stackPanel);
}
PagedCollectionView itemListView = new PagedCollectionView(newsStackPanel.Children);
newsPager.Source = itemListView;
and all of it goes here
<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded" MaxWidth="1100">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="2"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<RichTextBox Name="contentRTB" MaxWidth="1000" Margin="10, 30, 10, 30" Grid.Column="2"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
TextWrapping="Wrap"
Style="{StaticResource RichTextBoxStyle}" IsReadOnly="True"/>
<Rectangle Grid.Column="1" Margin="0,10"
Fill="#FF0067C6"/>
<TextBlock Name="header" Foreground="#FF0067C6" FontSize="18" FontFamily="Verdana" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="0"></TextBlock>
<sdk:DataPager x:Name="newsPager"
DisplayMode="FirstLastNumeric"
Background="#FF0067C6"
PageSize="3"
AutoEllipsis="True"
NumericButtonCount="3"/>
<StackPanel Name="newsStackPanel" Grid.Column="0" Orientation="Vertical" Margin="0,50,0,0"/>
</Grid>
The newsPager displayes (correctly) 2 pages because i have currently 5 news and the pageSize is set to 3 but they are all displayed on the same page so I dont get the desired paging... how can i fix it
Your code is adding all the items to a StackPanel, then it is putting that StackPanel inside another StackPanel called "newsStackPanel" below the DataPager. So, right now, the DataPager has nothing to do with the display of your news articles, and you won't be seeing any paging happening.
Instead, take a look at the DataPager sample code here:
http://msdn.microsoft.com/en-us/library/system.windows.controls.datapager(VS.95).aspx#Y9406
You'll need to modify that sample code to contain a list of StackPanels like this:
List<StackPanel> itemList = new List<StackPanel>();
Then, for each of your news items, add them to that list instead of an outer StackPanel:
itemList.Add(stackPanel);
You'll then wrap that up and bind it to both your data pager and a new list control:
// Wrap the itemList in a PagedCollectionView for paging functionality
PagedCollectionView itemListView = new PagedCollectionView(itemList);
// Set the DataPager and ListBox to the same data source.
newsPager.Source = itemListView;
listBox1.ItemsSource = itemListView;
The sample uses a ListBox called "listBox1". You have lots of choices there. Perhaps replace the "newsStackPanel" with a ListBox called "newsList".
OK, that should be enough to get you through this.
Now for a little more homework:
You should really consider switching this to the MVVM pattern where you bind these values and template them instead of making UI controls in C#. This results in much cleaner code, enables much easier reuse, improves testability, and so on. There are a million zillion articles on the web for this. Here is one from MS:
http://msdn.microsoft.com/en-us/library/gg430869(v=PandP.40).aspx
I don't know if the DataPager control you're using handles the paging completely.
You could only add the news items that are on the page you want to view to the stack panel.
One easy way to do that could be to use LINQ in your for each, something like:
foreach (Model.News news in s.Skip(newsPager.PageSize * newsPager.PageIndex).Take(newsPager.PageSize))
you'd have to reinitialize the items in the pager when the page index changes then too.

Categories

Resources