Basically, I am reading a value from an xml file and displaying that value in a text box. This text box is editable so the user can make changes to it and when the session ends that value gets stored back in the xml file.
I know that the values correctly get stored and loaded to the text box. But I'm baffled as to why I cannot see the bound value that should be displayed in the text box..
This is the text box:
<UserControl x:Class="test.myView"
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:ui="clr-namespace:test.myView"
xmlns:local="test.myControls;assembly=test.mycontrols">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style.xaml"/>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel Margin="8">
<TextBlock Text="Starting URL"/>
<TextBox Margin="0,5" FontSize="12" Height="30" Width="360" Text="{Binding myValue, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Style="{StaticResource WaterMarkTextBox}" local:WaterMarkTextHelper.WatermarkText="ENTER Value" />
</StackPanel>
This is the INotifyPropertyChanged:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaiseChangeNotification(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
This is the property im binding to:
public string myValue
{
get { return _settings.myValue; }
set { _settings.myValue= value; }
}
I think it maybe because the value of the text box to empty before the code reaches the part where the start url is set using data binding. Does there exist a validate command in wpf that forces it to view the most up to date value?
There is not enough information to know the exact problem, but there are a few things to check when this sort of things happen.
Check your Output window in Visual Studio. This will give you any binding errors. This will help solve some of the following problems:
Not having your property set to public
Typo with your property name
Not having the DataContext set
Make sure your DataContext implements the INotifyPropertyChanged interface. This is required by the implementation of WPF to update the binding. You would do this like the following:
public class YourDataContext : INotifyPropertyChanged
{
private object _myvalue;
public object myvalue
{
get
{
return _myvalue;
}
set
{
if (_myvalue == value)
return;
_myvalue = value;
OnPropertyChanged("myvalue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
You can also look up several strategies to simplify this, like INotifyPropertyChanged weaving or a BaseViewModel class.
Edit
If myvalue is in your ViewModel that inherits from your ViewModelBase then all you need to do is change the implementation of your property to:
public string myValue
{
get
{
return _settings.myValue;
}
set
{
if (_settings.myValue == value)
return;
_settings.myValue = value;
RaiseChangeNotification("myValue");
}
}
Try to add one dummy converter and see if binding is getting fired when you change value from UI textbox (Convert back method needs to be executed). Else take help of snoop (http://snoopwpf.codeplex.com/) This will help you check status of binding.
And add RaiseNotification in setter if you want to update data from source to target.
public string myValue
{
get { return _settings.myValue; }
set { _settings.myValue= value; RaiseChangeNotification("myValue") }
}
Related
I have a bunch of textboxes I'm trying to bind to strings in my viewmodel. I thought I had everything set up correctly, but nothing is appearing in the textboxes.
Here's my XAML and one of the textboxes I'm trying to bind.
<Window x:Class="Server.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:l="clr-namespace:Server"
xmlns:viewmodel="clr-namespace:Server.ViewModels"
Title="MainWindow">
<Window.DataContext>
<viewmodel:MainWindowViewModel />
</Window.DataContext>
<TextBlock Name="ShipLatTB"
FontSize="17"
Text="{Binding Path=CurrentShipLat, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Here's the viewmodel:
namespace Server.ViewModels
{
class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _currentShipLat;
public string CurrentShipLat
{
get { return _currentShipLat; }
set { _currentShipLat = value; OnPropertyChanged("CurrentShipLat"); }
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
I tested to make sure data is actually in '_currentShipLat' by setting it equal to "test" in a command, and debugged to verify it. Not sure what else is wrong?
Note: This textbox is supposed to be able to dynamically update.
Edit: How about giving a reason for the downvote and voting to close? That doesn't help anyone.
Make sure you set the field _currentShipLat before the WPF window is initialized.
If you do it after initialisation of the window, WPF will never 'see' this change because it doesn't trigger the property changed event. Either make sure the field is set before the window is initialized or use the setter of the property instead of directly setting the field.
I have an issue whereby when I update the text on a Comboboxitem it isnt instantly reflected on the UI. One has to click the Combobox to show the items (which have the correct text). Any ideas why? Note this exact code works perfectly in WPF
The property that defines the string to show
public string NormallyOpenString
{
get
{
if (this.IsInput)
{
return "High";
}
else if (this.IsRelay)
{
return "Open";
}
else
{
return "Open (High)";
}
}
}
Which is bound to a Combobox like so
<ComboBox SelectedIndex="{Binding Normally, Mode=TwoWay}" >
<ComboBoxItem Content="{Binding NormallyOpenString}" />
<ComboBoxItem Content="{Binding NormallyClosedString}" />
</ComboBox>
When another combobox changes I want to update the text as it changes what IsInput / IsRelay is. I do this via NotifyPropertyChanged like so
this.NotifyPropertyChanged("NormallyOpenString");
this.NotifyPropertyChanged("NormallyClosedOpenString");
this.NotifyPropertyChanged("Normally");
I've never done it that way, so I can't vouch for it. This is how I do property change notification:
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
private string normallyOpenString = "I'm an open string!";
public string NormallyOpenString
{
get { return normallyOpenString; }
set
{
normallyOpenString = value;
RaisePropertyChanged("NormallyOpenString");
}
}
}
So now, whenever anyone calls your setter, anything bound to your property will be updated. So if it gets set from one binding, all other bindings that are also bound to it will be updated.
I think you should rather use the SelectedItem property.
I don't know if I would be informative enough, but I'm having a problem.
I bound an ObservableCollection to a normal Listbox, everything is working fine, but ImageInfo has a member (Source) which contains the place where the image is, and I need the Source member of the current selected item in the Listbox. However, I don't seem to have a clue where to start.
Maybe you need in your xaml something like <Image Source="{Binding ElementName=myListbox, Path=SelectedItem.Source}"> . Other examples and explanations related to binding here https://stackoverflow.com/a/1069389/1606534
Are you binding in normal mode to a property like: EG: < combobox itemssource={Binding Listing}/>? If so you really just need to have a public property exposed for the 'selecteditem' if memory serves. The real power in Observable Collection from my understanding of WPF is how things can change in real time and you can notice those changes when implementing INotifyPropertyChanged or INotifyCollectionChanged.
<combobox x:Name="mycombo" itemssource="{Binding itemsource}"
selecteditem="{Binding SelectedItem}" />
ViewModel property:
public string SelectedItem { get; set; }
However if you want your property to be noticed when it changes you need to implement INotifyPropertyChanged. Typically then in studios I have worked in they set a private variable at the top of the class and then use it in the get set and then use the public property in bindings.
public class example : INotifyPropertyChanged
{
private string _SelectedItem;
public string SelectedItem
{
get { return _SelectedItem; }
set
{
_SelectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
public void DoSomething()
{
Messagebox.Show("I selected: " + SelectedItem);
}
}
First up, is it possible to add a property to a WPF UserControl with no code behind?
If not, lets say I have a custom UserControl like this:
<UserControl x:Class="Example.Views.View"
xmlns:vm ="clr-Example.ViewModels"
xmlns:view ="clr-Example.Views"
... >
<UserControl.DataContext>
<vm:ViewModel/>
</UserControl.DataContext>
<Button Background="Transparent" Command="{Binding ClickAction}">
<Grid>
...
<Label Content="{Binding Description}"/>
</Grid>
</Button>
</UserControl>
With The ViewModel like this
public class ViewModel : INotifyPropertyChanged
{
private ICommand _clickAction;
public ICommand ClickAction
{
get { return _clickAction; }
set
{
if (_clickAction != value)
{
_clickAction = value;
RaisePropertyChanged("ClickAction");
};
}
}
private int _description;
public int Description
{
get { return _description; }
set
{
if (_description!= value)
{
_description = value;
RaisePropertyChanged("Description");
};
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
// take a copy to prevent thread issues
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I want to be able to set the Action like this:
...
<UserControl.Resources>
<ResourceDictionary>
<command:ButtonGotClicked x:Key="gotClicked" />
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<view:FuelDispenserView ClickAction="{StaticResource gotClicked}"/>
</Grid> ...
Without Code behind.
Currently I use this ugly code to achive my goal but I don't like it.
public partial class View : UserControl
{
public View()
{
InitializeComponent();
}
public ICommand ClickAction {
get {
return ((ViewModel)(this.DataContext)).ClickAction;
}
set {
((ViewModel)(this.DataContext)).ClickAction = value;
}
}
}
Does anybody have a better Idea how to do this?
P.S. This is not just meant for this Action. I have different Properties I need to add.
You can use attached properties logic to add custom properties to your user control, but It looks like you have to define different behavior for ClickAction in different views, so I'm not sure it would be useful for you. I suggest you to use routed command and command bindings - it may be helpful in this case.
In WPF I have a collection of bool? values and I want to bind each of these to a separate checkbox programmatically. I want the bindings to be TwoWay so that changing the value of the individual item in the collection in code updates the check box and vice versa.
I have spent ages trying to figure out how to do this and I am completely stuck. With the following code the checkbox only gets the right value when the window is loaded and that's it. Changing the check box doesn't even update the value in the collection. (UPDATE: this appears to be a bug in .NET4 as the collection does get updated in an identical .NET3.5 project. UPDATE: Microsoft have confirmed the bug and that it will be fixed in the .NET4 release.)
Many thanks in advance for your help!
C#:
namespace MyNamespace
{
public partial class MyWindow : Window, INotifyPropertyChanged
{
public MyWindow()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public List<bool?> myCollection = new List<bool?>
{ true, false, true, false, true, false };
public List<bool?> MyCollection
{
get { return myCollection; }
set { myCollection = value; }
}
}
}
XAML:
<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}">
There are a few things that need changing here to get this to work. Firstly you'll need to wrap your boolean value in an object that implements the INotifyPropertyChanged interface in order to get the change notification that you are looking for. Currently you are binding to boolean values in your collection which do not implement the interface. To do this you could create a wrapper class like so :
public class Wrapper: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool val = false;
public bool Val
{
get { return val; }
set
{
val = value;
this.OnPropertyChanged("Val");
}
}
public Wrapper(bool val)
{
this.val = val;
}
}
You'll then want to create these objects in your form instead of a list of booleans. You may also want to use an observable collection instead of a list so that notification of items being added and removed are sent. This is shown below:
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
private ObservableCollection<Wrapper> myCollection = new ObservableCollection<Wrapper>()
{new Wrapper(true), new Wrapper(false), new Wrapper(true)};
public ObservableCollection<Wrapper> MyCollection
{
get { return myCollection; }
}
The next thing to do is to display a list of check boxes in your ui. To do this WPF provides itemscontrols. ListBox is an itemscontrol so we can use this as a starting point. Set the itemssource of a listbox to be MyCollection. We then need to define how each Wrapper object is going to be displayed in the list box and this can be done with a datatemplate which is created in the windows resources. This is shown below :
<Window.Resources>
<DataTemplate x:Key="myCollectionItems">
<CheckBox IsChecked="{Binding Path=Val, Mode=TwoWay}"></CheckBox>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=MyCollection}" ItemTemplate="{StaticResource myCollectionItems}"></ListBox>
</Grid>
This should get you up and running with a simple demo of checkboxes that have values bound to a list of booleans.
What makes you think it's not working? It's working for me :)
Here's my test XAML:
<UniformGrid>
<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"/>
<ListBox ItemsSource="{Binding MyCollection}"/>
<Button Content="Test" Click="Button_Click"/>
</UniformGrid>
Here's my code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
}
(the rest is the same as yours)
I placed a breakpoint on Button_Click and checked MyCollection[0] it was updated according to the IsChecked value of the CheckBox.
Try changing your collection type from List<bool?> to ObservableCollection<bool?> perhaps that is the reason you think it's not working for you (the fact that changes to the collection are not reflected anywhere else in your view).
Change your List<bool?> to an ObservableCollection<bool?>. A List does not raise the change notifications that WPF needs to update the UI. An ObservableCollection does. This handles the case where the list entry is changed and the CheckBox needs to update accordingly.
In the other direction, it works for me even with a List<bool?> -- i.e. toggling the checkbox modifies the value in the collection. Your binding syntax is certainly correct.