I try to learn WPF, I have problem with basic binding, at the beginning I want to set bind in code behind. May anyone know what I make wrong?
Fils CS
public partial class BindInCodeBehind : Window, INotifyPropertyChanged
{
private string _myText;
public string MyText
{
get { return _myText; }
set
{
_myText = value;
OnPropertyChanged("MyText");
}
}
public BindInCodeBehind()
{
InitializeComponent();
var bind = new Binding();
bind.Source = MyText;
bind.Path = new PropertyPath("Content");
MyLabel.SetBinding(Label.ContentProperty, bind);
MyText = "New tekst";
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
File XAML
<Window x:Class="WpfBindingLearn.BindInCodeBehind"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BindInCodeBehind" Height="300" Width="300">
<Grid>
<Label Name="MyLabel" Content="Wait for binding"></Label>
</Grid>
</Window>
Path is set in relation to current binding source. Your source (which is a String) does not have Content property. You can set Source to Window and Path to MyText
var bind = new Binding();
bind.Source = this;
bind.Path = new PropertyPath("MyText");
Related
I use WPF MVVM and have a Binding in my TabControll like this (XAML):
<TabControl SelectedIndex="{Binding SelectedTabIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, IsAsync=True}"
My Property looks like that:
private int _selectedTabIndex;
public int SelectedTabIndex
{
get { return _selectedTabIndex; }
set
{
if (TestbenchValidationCheck == true)
{
_selectedTabIndex = value;
OnPropertyChanged("SelectedTabIndex");
}
else
{
_selectedTabIndex = 0;
OnPropertyChanged("SelectedTabIndex");
}
}
}
If I switch the tab of the TabControll, then I don't see any content in the tab... if I change it more times and have luck, than I can see the tab content. What is the problem?
FYI:
If I delete the "IsAsync=true" attribute (in XAML code), then I am not able to switch the tab, i don't know why. Please note: I dont really want to use the IsAsync attribute, if there is another solution.
This is my OnPropertyChanged handler:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
This is my Codebehind:
public partial class MainWindow : Window
{
public MainWindow(object obj)
{
DataContext = obj;
InitializeComponent();
SetBindingForCBXLists();
}
private void SetBindingForCBXLists()
{
var binding = new Binding();
binding.Path = new PropertyPath("Element");
binding.Source = DataContext;
BindingOperations.SetBinding(PortListBox, DataGridComboBoxColumn.ItemsSourceProperty, binding);
var binding2 = new Binding();
binding2.Path = new PropertyPath("Psc.CanTypes.Element");
binding2.Source = DataContext;
BindingOperations.SetBinding(TypeListBox, DataGridComboBoxColumn.ItemsSourceProperty, binding2);
}
public MainWindow()
{
}
}
I am new to WPF. I have binded the source class properties to target controls successfully. But whenever the properties value changes the UI controls not reflecting the updated data. Please help
WPF Code:
<Label Name="Panel_ch1Mode" Content="{Binding Path=Mode, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" FontFamily="Roboto Regular" FontSize="16" Foreground="#FFFFFF"/>
My Class:
public class ClassName: INotifyPropertyChanged
{
//Auto Refresh
private string mode;
public string Mode
{
get
{
return this.mode;
}
set
{
this.mode = value;
NotifyPropertyChanged("Mode");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Try this: Just remove from xaml the UpdateSourceTrigger=PropertyChanged, Mode=TwoWay. )
Improve your implementation of INotifyPropertyChanged linke this:
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
In code behind please check if the ViewModel is "wired" to the View:
public YourView()
{
InitializeComponent();
DataContext = new ClassName();
}
You have to keep in mind that a binding is always related to DataContext.
I have created A treeView named ValueTreeView in xaml code it uses the datatemplate created in the following code,that binds entirely to a generic class ValueHolder
This is the class used for binding
public class ValueHolder
{
public string VHName{ get; set; }
public string VHValue{ get; set; }
}
This is the user control having the treeview
public partial class UserControl1 : UserControl
{
ObservableCollection<ValueHolder> source;
public UserControl1()
{
InitializeComponent();
source= new ObservableCollection<ValueHolder>();
//Data Template for the treeView
DataTemplate cardLayout = new DataTemplate();
cardLayout.DataType = typeof(ValueHolder);
FrameworkElementFactory ValueStack= new FrameworkElementFactory(typeof(StackPanel));
ValueStack.Name = "Details";
ValueStack.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
FrameworkElementFactory VName= new FrameworkElementFactory(typeof(TextBlock));
VName.SetBinding(TextBlock.TextProperty, new Binding("VHName"));
ValueStack.AppendChild(VName);
FrameworkElementFactory Space = new FrameworkElementFactory(typeof(TextBlock));
Space.SetValue(TextBlock.WidthProperty, 10.0);
ValueStack.AppendChild(Space);
FrameworkElementFactory VValue= new FrameworkElementFactory(typeof(TextBlock));
VValue.SetBinding(TextBlock.TextProperty, new Binding("VHValue"));
ValueStack.AppendChild(VValue);
cardLayout.VisualTree = ValueStack;
ValueTreeView.ItemTemplate = cardLayout;
//Initializing the TreeViewItems
ValueHolder vh1 = new ValueHolder() { VHName = "VH1", VHValue = "456"};
ValueHolder vh2 = new ValueHolder() { VHName = "VH2", VHValue = "578"};
ValueHolder vh3 = new ValueHolder() { VHName = "VH3", VHValue = "235"};
source.Add(vh1);
source.Add(vh2);
source.Add(vh3);
ValueTreeView.ItemsSource = source;
}
The below is the event handler called when the selection item changed
private void ValueTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var s=((ValueHolder)((TreeView)sender).SelectedItem);
if(s.VHName=="VH2")
s.VHValue = "111";
}
}
The two text blocks in each TreeViewItem are bound to the two class variables.
My problem is when I change the Value of the Class property,it is not reflected in the UI,even though I use ObservableCollection for the Item source of the TreeView.
The event handler changes the VHValue property of the class and it is getting changed in the backend,yet not reflected in the UI
My xaml code:
<UserControl x:Class="Checker.UserControl1"
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">
<Grid>
<TreeView x:Name="ValueTreeView" SelectedItemChanged="ValueTreeView_SelectedItemChanged">
</TreeView>
</Grid>
</UserControl>
ObservableCollection works only for collection changes not the changes of items in collection. You need to implement INotifyPropertyChanged interface for ValueHolder class
more details here
public class ValueHolder : INotifyPropertyChanged
{
private string _VHName;
private string _VHValue;
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public string VHName
{
get { return _VHName; }
set
{
_VHName = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("VHName");
}
}
public string VHValue
{
get { return _VHValue; }
set
{
_VHValue= value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("VHValue");
}
}
// 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'm trying to create a simple WPF Application using data binding.
The code seems fine, but my view is not updating when I'm updating my property.
Here's my XAML:
<Window x:Class="Calculator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:calculator="clr-namespace:Calculator"
Title="MainWindow" Height="350" Width="525"
Name="MainWindowName">
<Grid>
<Label Name="MyLabel" Background="LightGray" FontSize="17pt" HorizontalContentAlignment="Right" Margin="10,10,10,0" VerticalAlignment="Top" Height="40"
Content="{Binding Path=CalculatorOutput, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</Window>
Here's my code-behind:
namespace Calculator
{
public partial class MainWindow
{
public MainWindow()
{
DataContext = new CalculatorViewModel();
InitializeComponent();
}
}
}
Here's my view-model
namespace Calculator
{
public class CalculatorViewModel : INotifyPropertyChanged
{
private String _calculatorOutput;
private String CalculatorOutput
{
set
{
_calculatorOutput = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I'm can't see what I am missing here?? o.O
CalculatorOutput has no getter. How should the View get the value? The Property has to be public as well.
public String CalculatorOutput
{
get { return _calculatorOutput; }
set
{
_calculatorOutput = value;
NotifyPropertyChanged();
}
}
I'm creating a UserControl object, and i'm trying to assign values using Binding (with PropertyChanged). I made a prototype, when I assign value in ViewModel , the value does not appear or modify the UserControl component, but if I assign the value directly in the UserControl object that is in view, the modification works. I would like to understand what I'm doing wrong, since works fine if i just add an object on my window and binding directly (again, using PropertyChanged).
Follow the code below.
Thanks for any help.
Best Regards,
Gustavo.
UserControl:
<UserControl x:Class="WpfControlLibrary1.UserControl1"
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="30" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding Title}" />
</Grid>
</UserControl>
Code Behind of User Control:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
#region Title Property
public static String GetTitle(DependencyObject obj)
{
return (String)obj.GetValue(TitleProperty);
}
public static void SetTitle(DependencyObject obj, String value)
{
obj.SetValue(TitleProperty, value);
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.RegisterAttached(
"Title",
typeof(String),
typeof(UserControl1),
new FrameworkPropertyMetadata(TitleChangedCallback)
);
private static void TitleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UserControl1 _this = (d as UserControl1);
}
private String title;
public String Title
{
get { return title; }
set
{
title = value;
OnPropertyChanged("Title");
}
}
#endregion
#region INotifyPropertyChanged event and method
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
** My Window: **
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<uc:UserControl1 Title="{Binding TitleVM, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Window>
** My Code-Behind/ViewModel: **
public partial class MainWindow : INotifyPropertyChanged
{
// Notify WPF that Counter changed
public event PropertyChangedEventHandler PropertyChanged;
public MainWindow()
{
InitializeComponent();
TitleVM = "açsldkfjasçldkfj";
}
private String titleVM;
public String TitleVM
{
get { return titleVM; }
set
{
titleVM = value;
OnPropertyChanged("TitleVM");
}
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Your Window doesnt have a DataContext. Bindings cannot be resolved.
Try this:
public MainWindow()
{
InitializeComponent();
DataContext = this; //This is what you're missing!
TitleVM = "açsldkfjasçldkfj";
}
Edit:
You're also missing the same thing in the UserControl
public UserControl1()
{
InitializeComponent();
DataContext = this;
}
With help of HighCore, i've found one problem, and the other problem was my UserControl doesn't have a name defined.
Just put:
x:Name="UserControl"
Into XAML of UserControl and will work. Also, i've modified my code behind to this:
public String Title
{
get { return (String)base.GetValue(TitleProperty); }
set { base.SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.RegisterAttached(
"Title",
typeof(String),
typeof(UserControl1),
new FrameworkPropertyMetadata(null)
);
A clean code to our eyes.
PS: There's no need to put:
DataContext = this;
On Code Behind of UserControl. At least here only result on bug, no values was comming.
Thanks HighCore for you help.