Im having some problems with binding in wpf/xaml. Have this simple file:
<Window x:Class="test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBlock Height="21" Foreground="Black" Margin="74,98,84,0" Name="textBlock1" VerticalAlignment="Top" Text="{Binding MyText}" />
</Grid>
</Window>
Where i want to bind the content of the textblock to my property "MyText". My code looks like this:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
public string MyText
{
get { return "This is a test"; }
}
}
All in all very simple, but when i start the textblock has no content - howcome?
you need an element name in your binding:
<Window ... x:Name="ThisWindow"...>
<TextBlock ... Text="{Binding MyText, ElementName=ThisWindow}" />
If I'm remembering my WPF binding syntax correctly, I believe your binding expression should read Text="{Binding Path=MyText}"
There are a number of ways to accomplish this. Probably the easiest for something as simple as this form is:
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
Related
On the MainWindow of my WPF application I have a simple listBox that is databound to an ObservableCollection. The ObservableCollection contains members of a simple "Product" class with one string-property. The goal is to show the text that is stored in the "PName" property of all Products of the ObservableCollection.
The MainWindow.xaml:
<Window x:Class="BindingCheck.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:BindingCheck"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="listBox1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label FontSize="26" Content="{Binding Path=PName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
The MainWindow.Xaml.Cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace BindingCheck
{
public class Product
{
private string pName;
public string PName
{
get { return pName; }
}
public Product(string pname)
{
pName = pname;
}
}
public partial class MainWindow : Window
{
private ObservableCollection<Product> products;
public MainWindow()
{
InitializeComponent();
products = new ObservableCollection<Product>();
products.Add(new Product("Toaster"));
products.Add(new Product("Big_Toaster"));
products.Add(new Product("Very_Big_Toaster"));
this.DataContext = products;
}
}
}
And now my question: Why is only every second '_' character shown in the listBox output? The Output-Items should be: "Toaster", "Big_Toaster" and "Very_Big_Toaster" but however I get another output:
Output-Items in listBox: Toaster, BigToaster, VeryBig_Toaster
See below code:
<StackPanel>
<Label Content="_first_second" Target="{Binding ElementName=txtbox}"/>
<TextBox Name="txtbox" Width="100" Height="50"/>
</StackPanel>
Now after the screen is Loaded press key 'f' any you'll see the Focus is set in the TextBox.
Cause the the content of Label is treated as AccessText for Label
here and according to AccessText definition first '' char means
the Accesskey to element and '' is not visible.
use below links for ref:
MSDN on AccessText
AccessText example
Whatsup, I'm new to wpf technology and im having trouble to find out how to popup a message on screen when there is a change on the User property. (Except that, the code works perfect).
*My goal is to register an exsisting event that takes care of it and NOT to do it in the MyData class by rewriting the 'Set'.
xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel x:Name="MyGrid1">
<StackPanel.Resources>
<local:MyData x:Key="mySource1"
User="Arik2" />
</StackPanel.Resources>
<TextBox x:Name="target1"
Grid.Row="1"
Grid.Column="2"
Text="{Binding Source={StaticResource mySource1}, Path=User,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="target2"
Grid.Row="2"
Grid.Column="2"
Text="{Binding Source={StaticResource mySource1}, Path=User,Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Window>
Thats my app code:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MyData
{
public string User { get; set; }
}
}
Thank you all.
For the textboxes you have you can always open a message window in a textchanged event handler.
For example
<TextBox TextChanged="txt_TextChanged" >
Private Sub txt_TextChanged(sender As System.Object, e As System.Windows.Controls.TextChangedEventArgs)
MessageBox.Show("Value changed")
End Sub
Note this is probably what you are looking for but is triggering off the text in the box changing not the property itself. If you use anything like validation and input invalid data this event will fire but the text will not change.
I think you can use the sourcechanged event to get exactly what you want.
What simple thing am I missing here? Why doesn't my copy display on the screen?
<Window x:Class="DeleteThis.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>
<StackPanel>
<TextBlock Text="{Binding Path=SomeCopy}" Height="35" Width="100" Margin="10"/>
</StackPanel>
</Grid>
and my code-behind.
public partial class MainWindow : Window
{
private string _someCopy;
public string SomeCopy
{
get
{
return _someCopy;
}
set
{
_someCopy = value;
}
}
public MainWindow()
{
InitializeComponent();
SomeCopy = "why doesn't this display";
}
}
You never set the DataContext of the Window. Change your XAML to this...
<TextBlock Text="{Binding}" Height="35" Width="100" Margin="10"/>
...and change your code behind to add the DataContext line...
public MainWindow()
{
InitializeComponent();
SomeCopy = "why doesn't this display";
this.DataContext = SomeCopy;
}
Your current issue has nothing to do with needing a DependencyProperty as mentioned in the other answers.
WPF never finds out that the property changed.
To fix it, you can turn the property into a dependency property.
EDIT: You also need to bind to the property on the Window itself, like this
<TextBlock Text="{Binding Path=SomeCopy, RelativeSource={RelativeSource Self}}" ... />
SLaks's answer is the correct one. But making dependency properties manually is annoying, so I link you to my favorite solution: A custom PostSharp NotifyPropertyChangedAttribute that, when used in conjunction with PostSharp, makes all the properties of any given class into dependency properties.
I'm learning WPF and would like to have a collection similar to a LinkedList, to where I can add and remove strings. And I want to have a ListView that listen to that collection with databinding. How can I do bind a simple list collection to a ListView in XAML?
My idea (not working) is something like this:
<Window x:Class="TestApp.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">
<Window.Resources>
<LinkedList x:Key="myList"></LinkedList> //Wrong
<Window.Resources>
<Grid>
<ListView Height="100" HorizontalAlignment="Left" Margin="88,134,0,0"
Name="listView1" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource myList}}"/> //Wrong
</Grid>
</Window>
All my code (updated version, not working):
<Window x:Class="TestApp.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>
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0"
Name="textBox1" VerticalAlignment="Top" Width="120" />
<Button Content="Button" Height="23" HorizontalAlignment="Right"
Margin="0,12,290,0" Name="button1" VerticalAlignment="Top" Width="75"
Click="button1_Click" />
<ListView Height="100" HorizontalAlignment="Left" Margin="88,134,0,0"
Name="listView1" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding myList}"/>
</Grid>
</Window>
C#-code:
namespace TestApp
{
public partial class MainWindow : Window
{
ObservableCollection<string> myList = new ObservableCollection<string>();
public MainWindow()
{
InitializeComponent();
myList.Add("first string");
}
private void button1_Click(object sender, RoutedEventArgs e)
{
myList.Add(textBox1.Text);
textBox1.Text = myList.Count+"st";
}
}
}
The approach selected as an answer works fine... but I don't specifically like having to specify the DataContext programmatically while setting everything else in XAML, I don't feel like it's "proper" (maybe this is just me). So for the next person, or anyone else who thinks like me and finds this off a search engine (like i did), here is the way to do it in XAML:
C#
public sealed partial class MainPage : Page
{
public ObservableCollection<string> Messages { get; set; }
public MainPage()
{
this.Messages = new ObservableCollection<string>();
this.InitializeComponent();
}
}
XAML
<Window
....
DataContext="{Binding RelativeSource={RelativeSource Self}}"
...>
<ListView ItemsSource="{Binding Messages}" ... />
</Window>
To be honest I think {Binding RelativeSource={RelativeSource Self}} should be the default value any top level element's (Page, Window, etc...) DataConext because it is simply how a lot of people expect it to work, I know it's how I assume it would work. Honestly, I feel like {Binding RelativeSource={RelativeSource Self}} is a bit verbose and almost long for a shorter syntax.
You can only databind to public properties and you need to set the DataContext.
public partial class MainWindow : Window
{
public ObservableCollection<string> myList { get; private set; }
public MainWindow()
{
InitializeComponent();
myList = new ObservableCollection<string>();
myList.Add("first string");
DataContext = this;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
myList.Add(textBox1.Text);
textBox1.Text = myList.Count + "st";
}
}
<StackPanel x:Name="stkWaitingPatients" Width="300" Margin="0,0,0,-3"
DataContext="{Binding Mode=OneWay, Source={StaticResource local:oPatients}}">
I'm getting StaticResource reference 'local:oPatients' was not found.
Here is the codebehind:
public partial class MainWindow : Window
{
ListBox _activeListBox;
clsPatients oPatients;
public MainWindow()
{
oPatients = new clsPatients(true);
...
To be able to address the object as a StaticResource, it needs to be in a resource dictionary. However, since you're creating the object in MainWindow's constructor, you can set the DataContext in the code-behind like so.
oPatients = new clsPatients(true);
stkWaitingPatients.DataContext = oPatients;
And then change the Binding to this:
{Binding Mode=OneWay}
This is an ok practice if you're not going to be changing the DataContext again, otherwise you'd want a more flexible solution.
Edit: You mentioned ObjectDataProvider in your comment. Here's how you'd do that. First, add an xmlns:sys to the Window for the System namespace (I'm assuming you already have one for xmlns:local):
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Then you can add an ObjectDataProvider to your resource dictionary like this:
<Window.Resources>
<ObjectDataProvider
x:Key="bindingPatients"
ObjectType="{x:Type local:clsPatients}">
<ObjectDataProvider.ConstructorParameters>
<sys:Boolean>True</sys:Boolean>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
</Window.Resources>
And refer to it in a Binding with the StaticResource markup like this, using the same string we specified in the x:Key attached property we gave it in the dictionary:
{Binding Source={StaticResouce bindingPatients}, Mode=OneWay}
Edit 2: Ok, you posted more code in your answer, and now I know why it's throwing an exception during the constructor. You're attempting to do this...
lstWaitingPatients.DataContext = oPatients;
... but lstWaitingPatients doesn't actually exist until after this.InitializeComponent() finishes. InitializeComponent() loads the XAML and does a bunch of other things. Unless you really need to do something before all of that, put custom startup code after the call to InitalizeComponent() or in an event handler for Window's Loaded event.
The following sets the ItemsSource in Code Behind and correctly handles the DataBinding:
public partial class MainWindow : Window
{
public MainWindow()
{
clsPatients oPatients = new clsPatients(true);
//assuming oPatients implements IEnumerable
this.lstWaitingPatients.ItemsSource = oPatients;
And the XAML:
<ListBox x:Name="lstWaitingPatients"
IsSynchronizedWithCurrentItem="true"
ItemTemplate="{StaticResource WaitingPatientsItemTemplate}"
FontSize="21.333" Height="423.291"
ScrollViewer.VerticalScrollBarVisibility="Visible"
GotFocus="lstWaitingPatients_GotFocus"
/>
Now, I can't get this to work...I get a general Windows startup error.
Here is the codebehind with the Initializer and the class being instantiated:
public partial class MainWindow : Window
{
ListBox _activeListBox;
public MainWindow()
{
clsPatients oPatients = new clsPatients(true);
lstWaitingPatients.DataContext = oPatients;
this.InitializeComponent();
Here's the top of my XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Orista_Charting"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
x:Class="Orista_Charting.MainWindow"
x:Name="windowMain"
Title="Orista Chart"
Width="1024" Height="768" Topmost="True" WindowStartupLocation="CenterScreen" Activated="MainWindow_Activated" >
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/ButtonStyles.xaml"/>
<ResourceDictionary Source="Resources/OtherResources.xaml"/>
<ResourceDictionary Source="Resources/TextBlockStyles.xaml"/>
<ResourceDictionary Source="Resources/Converters.xaml"/>
</ResourceDictionary.MergedDictionaries>
Here's the pertinent XAML, as you see, I went ahead and moved the DataContext down to the ListBox from the StackPanel. This doesn't run, but it does render in Design View (however, with no data present in the ListBox):
<!-- Waiting Patients List -->
<Border BorderThickness="1,1,1,1" BorderBrush="#FF000000" Padding="10,10,10,10"
CornerRadius="10,10,10,10" Background="#FFFFFFFF" Margin="15.245,187.043,0,41.957" HorizontalAlignment="Left" >
<StackPanel x:Name="stkWaitingPatients" Width="300" Margin="0,0,0,-3">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Waiting Patients:" VerticalAlignment="Center" FontSize="21.333" Margin="0,0,0,20"/>
<TextBlock HorizontalAlignment="Right" Margin="0,0,38.245,0" Width="139" Height="16"
Text="Minutes Waiting" TextWrapping="Wrap" Foreground="#FF9C2525" FontWeight="Bold" VerticalAlignment="Bottom"
TextAlignment="Right"/>
<!-- Too be implemented, this is the wait animation -->
<!--<Image x:Name="PollGif" Visibility="{Binding Loading}"
HorizontalAlignment="Left" Margin="100,0,0,0" Width="42.5" Height="42.5"
Source="Images/loading-gif-animation.gif" Stretch="Fill"/>-->
</StackPanel>
<ListBox x:Name="lstWaitingPatients"
DataContext="{Binding Mode=OneWay}" ItemsSource="{Binding Mode=OneWay}"
IsSynchronizedWithCurrentItem="true"
ItemTemplate="{StaticResource WaitingPatientsItemTemplate}"
FontSize="21.333" Height="423.291" ScrollViewer.VerticalScrollBarVisibility="Visible"
GotFocus="lstWaitingPatients_GotFocus"
/>
</StackPanel>
</Border>
Ok, but if I just take comment out the assigment line in the codebehind, it does run (albeit with no data in the listbox):
public partial class MainWindow : Window
{
ListBox _activeListBox;
public MainWindow()
{
clsPatients oPatients = new clsPatients(true);
//lstWaitingPatients.DataContext = oPatients;
THANKS!