I have a business application (created from template) and I can change language dynamically by making ResourceWrapper INotifyPropertyChanged and then adding in code:
private void Language_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Thread.CurrentThread.CurrentCulture =
new CultureInfo(((ComboBoxItem)((ComboBox)sender).SelectedItem).Tag.ToString());
Thread.CurrentThread.CurrentUICulture =
new CultureInfo(((ComboBoxItem)((ComboBox)sender).SelectedItem).Tag.ToString());
((ResourceWrapper)App.Current.Resources["ResourceWrapper"]).ApplicationStrings =
new ApplicationStrings();
}
this works fine on resources referenced/binded in xaml files (i.e. MainPage frame), but it does not update references of anything I have declared in code i.e.
InfoLabel.Content = ApplicationStrings.SomeString
At the moment I'm not using ResourceWrapper. My question here is how can I change my code so it uses it and updates when ResourceWrapper change. I tried:
InfoLabel.Content = ((ResourceWrapper)App.Current.Resources["ResourceWrapper"])
.ApplicationStrings.SomeString
but it doesn't work.
Any ideas?
You would have to create a Binding in code. Something like this:
var b = new Binding("SomeString");
b.Source = ((ResourceWrapper)App.Current.Resources["ResourceWrapper"]).ApplicationStrings;
b.Mode = BindingMode.OneWay;
InfoLabel.SetBinding(ContentControl.ContentProperty, b);
Keep in mind that the class you bind to must implement INotifyPropertyChanged.
EDIT:
If you are worried about the amount of code, just create a helper method somewhere in your app:
public Binding GetResourceBinding(string key)
{
var b = new Binding(key);
b.Source = ((ResourceWrapper)App.Current.Resources["ResourceWrapper"]).ApplicationStrings;
b.Mode = BindingMode.OneWay;
return b;
}
And then use the helper method like this:
InfoLabel.SetBinding(ContentControl.ContentProperty, GetResourceBinding("SomeString"));
Related
I´ve a question regarding INotifyTaskCompletion (https://msdn.microsoft.com/en-us/magazine/dn605875.aspx).
When i use this patter in an UI, created in XAML everything works fine.
But when i want to use it in a UI generated by Code (C#) it doesen´t work.
Viewmodel is the same.
I have have a Test project in this Link.
https://github.com/marcuskammerlander/NotifyTaskCompletion
You can change the UI in App.xaml.cs
public Testpage()
{
//Work
this.BindingContext = new testpageViewModel();
TestCount.SetBinding(Label.TextProperty, new Binding("UrlByteCount.Result", BindingMode.OneWay));
//Doesent Work
//testpageViewModel viewModel = new testpageViewModel();
//this.BindingContext = viewModel;
//TestCount.SetBinding(Label.TextProperty, new Binding(nameof(viewModel.UrlByteCount.Result), BindingMode.OneWay));
Content = new StackLayout
{
Children = {
TestLabel, TestCount
}
};
}
Regards,
Marcus
After my balance label is initially bound to a number, changing the datasource again doesn't update the value again.
I want to update the a Windows Form Label automatically after the database object is changed and I re-pull it into the constructorData.BankAccount.
public class ConstructorData
{
public Client Client { get; set; }
public BankAccount BankAccount { get; set; }
}
private void frmTransaction_Load(object sender, EventArgs e)
{
// Pretend we populated constructor data already
// This line of code is working
bankAccountBindingSource.DataSource = constructorData.BankAccount;
}
private void lnkProcess_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
constructorData.BankAccount = db.BankAccounts.Where(x => x.BankAccountId == constructorData.BankAccount.BankAccountId).SingleOrDefault();
// What do I do here
// Doesn't work
bankAccountBindingSource.EndEdit();
bankAccountBindingSource.ResetBindings(false);
}
Auto generated code:
//
// lblAccountBalance
//
this.lblAccountBalance.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lblAccountBalance.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.bankAccountBindingSource, "Balance", true));
this.lblAccountBalance.Location = new System.Drawing.Point(482, 71);
this.lblAccountBalance.Name = "lblAccountBalance";
this.lblAccountBalance.Size = new System.Drawing.Size(196, 23);
this.lblAccountBalance.TabIndex = 7;
this.lblAccountBalance.Text = "label1";
Since here (inside the form load):
bankAccountBindingSource.DataSource = constructorData.BankAccount;
you bind directly to the BankAccount instance, even implementing INotifyPropertyChanged in ConstructorData class (as suggested in the comments) will not help.
With that design, anytime you assign a new BankAccount instance to the ConstructorData.BankAccount property (as in the shown code), you need also to set it as DataSource of the BindingSource used:
constructorData.BankAccount = db.BankAccounts.Where(x => x.BankAccountId == constructorData.BankAccount.BankAccountId).SingleOrDefault();
// What do I do here
bankAccountBindingSource.DataSource = constructorData.BankAccount;
Without Implementing INotifyPropertyChanged Ivan's answer is exactly what you need.
The reason is because you put an object in DataSource of binding source this way: BindingSource.DataSource = constructorData.BankAccount, so it uses the object which is in BankAccount property as data source. If you change the value of constructorData.BankAccount, you disd't changed the data source of BindingSource and it will contain the previous object. For example take a look at this code:
var a = new MyClass("1"); // ← constructorData.BankAccount = something;
var b = a; // ← bindingSource.DataSource = constructorData.BankAccount.
a = new MyClass("2"); // ← constructorData.BankAccount = something else;
What should contain b now? Do you expect b contains MyClass("1")? Surely no.
For more information take a look at this post:
Data Binding doesn't work when I assign a new object instance to the bound variable
Can I use INotifyPropertyChanged to solve the problem?
If you implement INotifyPropertyChanged in ConstructorData and change bindings this way, yes:
bankAccountBindingSource.DataSource = constructorData;
//...
this.lblAccountBalance.DataBindings.Add(new System.Windows.Forms.Binding("Text",
this.bankAccountBindingSource, "BankAccount.Balance", true));
I'm new to WP8 and follow many tutorials. For parts of the menu I use a viewModel with NotifyPropertyChanged. When I get my list of news articles it creates a viewModel and displays it in a longListSelector.
But also I want to make 1 HubTile with the image and some preview-text of the first article. Is there a nice way to send some event to the .xaml.cs? Or do I have to make another viewModel for this one HubTile and make a binding?
Ony try was to make such a variable:
private bool _isDataLoaded = false;
public bool IsDataLoaded
{
get
{
return _isDataLoaded;
}
set
{
if (value != _isDataLoaded)
{
_isDataLoaded = value;
NotifyPropertyChanged("IsDataLoaded");
}
}
}
The same thing is used with "IsLoading"-variable to create a loading-indicator in the systemTray:
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("MainPage_Loaded-Funktion");
Binding binding = new Binding("IsLoading") { Source = DataContext };
BindingOperations.SetBinding(
prog, ProgressIndicator.IsVisibleProperty, binding);
binding = new Binding("IsLoading") { Source = DataContext };
BindingOperations.SetBinding(
prog, ProgressIndicator.IsIndeterminateProperty, binding);
prog.Text = "Lade aktuelle Inhalte...";
}
Can I use this to call a function, when my variable is set and I get a notification?
The solution that helped me out was this:
<toolkit:HubTile Message="{Binding OnlineNews[0].TeaserText}"/>
Didn't know that you can access the viewModel like that. Thanks to Toni Petrina!
I've created a custom user control with a grid. I'd like to bind this grid once, and use it over and over again in my app. If I put the binding within the control, the data is retrieved as many times as I use the control. How do I bind it only once??
public ClientLookUp()
{
InitializeComponent();
vw_clientsTableAdapter.Fill(dsclientlkup.vw_clients); //This occurs as many times as I have the user control, instead of just once.
}
Well anything you put in the constructor will be executed every time you construct the object!
What about providing an Initialize method that you can call whenever you need to reload the data??
If you want to load the data only once, then load it either into a static variable or a separate class that is referenced by the control.
If you really want to use the same single grid in your control over and over, you could create a single, static grid, and have your ClientLookUp constructor add it to the right place—Panel, or whatever—whenever a new one is created.
Before you go do this road however, ask yourself if this is really what you want to do. Having the same identical grid existing in many places may cause you problems down the road. If you want to support in-grid editing, you'll find that changing one value changes the identical value in all your other grids..
EDIT
I tried getting the below code to work, but I'm not sure this approach will be possible. It seems as though the minute you try to attach the same UI element into more than one place, it gets moved out of the last place you put it; it doesn't look like you can have the same grid being in more than one place at once. This makes sense when you think about it.
Here's the code I tried. Maybe it will be of some use to you.
public UserControl1()
{
InitializeComponent();
this.Controls.Add(myStaticGridView);
myStaticGridView.Dock = DockStyle.Fill;
}
static DataGridView _staticGrid;
public DataGridView myStaticGridView
{
get
{
if (_staticGrid != null)
return _staticGrid;
_staticGrid = new DataGridView();
_staticGrid.Columns.Add("A", "A");
_staticGrid.Columns.Add("B", "B");
_staticGrid.Columns.Add("C", "C");
_staticGrid.Columns[0].DataPropertyName = "A";
_staticGrid.Columns[1].DataPropertyName = "B";
_staticGrid.Columns[2].DataPropertyName = "C";
_staticGrid.DataSource = new[] {
new { A = "someA", B = "someB", C = "someC"},
new { A = "someA", B = "someB", C = "someC"},
new { A = "someA", B = "someB", C = "someC"},
new { A = "someA", B = "someB", C = "someC"},
};
return _staticGrid;
}
}
And then loading the control like this:
private void button1_Click(object sender, EventArgs e)
{
flowLayoutPanel1.Controls.Add(new UserControl1());
}
I am using WinForms C#
Is there any way to get following behavior:
bind List to CheckedListBox
When I add elements to list CheckedList box refereshes
When I change CheckedListBox the list changes
I tried to do the following:
Constructor code:
checkedlistBox1.DataSource = a;
checkedlistBox1.DisplayMember = "Name";
checkedlistBox1.ValueMember = "Name";
Field:
List<Binder> a = new List<Binder> { new Binder { Name = "A" } };
On button1 click:
private void butto1_Click(object sender, EventArgs e)
{
a.Add(new Binder{Name = "B"});
checkedListBox1.Invalidate();
checkedListBox1.Update();
}
But the view does not update .
Thank You.
Change this line:
List<Binder> a = new List<Binder> { new Binder { Name = "A" } };
to this:
BindingList<Binder> a = new BindingList<Binder> { new Binder { Name = "A" } };
It will just work without any other changes.
The key is that BindingList<T> implements IBindingList, which will notify the control when the list changes. This allows the CheckedListBox control to update its state. This is two-way data binding.
Also, you could change these two lines:
checkedListBox1.Invalidate();
checkedListBox1.Update();
to this (more readable and essentially does the same thing):
checkedListBox1.Refresh();
Two things you may wish to look at:
Use a BindingList
Add a BindableAttribute to your Name property
Does your List<Bender> need to be some kind of observable collection, like ObservableCollection<Bender> instead?
The proper way of binding a checked listbox is:
List<YourType> data = new List<YourType>();
checkedListBox1.DataSource = new BindingList<YourType>(data);
checkedListBox1.DisplayMember = nameof(YourType.Name);
checkedListBox1.ValueMember = nameof(YourType.ID);
Note to self.
The issue i have every time binding it is that the properties DataSource, DisplayMember and ValueMember are not suggested by intellisense and i get confused.