At the very simplest level all I am trying to do is Data Bind TextBlock control (XAML). Am tying to get string from MyString (property defined in C# code behind) as a Text for TextBlock:
DisplayText disp = new DisplayText();
disp.MyString = "Hello";
public class DisplayText {
public string MyString {get;set;}
}
XAML code:
<TextBlock Grid.Column="1" Text="{Binding Path=MyString}" Foreground="Black"/>
But, Its not working:( Am searching for hours but could'nt get this simple thing done. Plz help!
In your XAML you need to define the DataContext.
For example:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Also, you'll need to implement INotifyChanged if you want the screen and model to stay in sync.
Have you seen the msdn article about data binding in Store Apps? http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464965.aspx
The example code shows how to do what you are describing and worked for me.
Related
I have been following some training videos and created a simple app with UWP and C#, and using UWP Databinding, unfortunately passing data from a textbox to a class property just doesn't work. Nothing happens. No data is passed, no errors generated.
So my class(everything stripped to relevant code) is
public class ChangeCalc
{
public string GoodsCost { get; set; }
public string Amountpaid { get; set; }
Under page is
<Page.DataContext>
<local:ChangeCalc />
</Page.DataContext>
Under my 2 TextBoxes I have
<TextBox
x:FieldModifier="public"
Text="{Binding Amountpaid, Mode=TwoWay}"
TextWrapping="Wrap" />
So it is all there.
If I just call it under the button Click event in the codebehind it works OK. Data passes, code runs.
myChangeCalc.GoodsCost = txtCost.Text;
myChangeCalc.Amountpaid = txtPaid.Text;
When is the databinding initiated? What event, if any, is missing?
Thanks for your help.
There is nothing being passed through. yet with the click event to the same properties, it passes OK.
This is because when you use data binding, you just give a data model as DataContext in where the property can be found to the TextBox, you didn't actually pass any real data to the TextBox. And when you use button click event, you create an instance "myChangeCalc" of this data model and pass a real data like "txtPaid.Text" to the property "Amountpaid" of this instance.
silverfighter, you don't have to implement INotifyPropertyChanged (what do I know I can't get it to work) The instructions say : Changes to TextBox.Text are sent to a two-way bound source when the TextBox loses focus, and not after every user keystroke.
Yes, but this change is from binding target to binding source, if you want change from binding source to binding target here, you must implement the INotifyPropertyChanged interface on the source object so that the source can report changes through events that the binding engine listens for.
So, as an example here:
<Page.Resources>
<local:ChangeCals x:Name="ccData" Amountpaid="111" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{StaticResource ccData}">
<TextBox
x:FieldModifier="public"
Text="{Binding Amountpaid, Mode=TwoWay}"
TextWrapping="Wrap" Height="50" />
</Grid>
You can create a instance of your data model in the page resources, and set this resource as the DataContext of Binding.
Another example:
<TextBox
x:FieldModifier="public"
Text="{Binding Amountpaid, Mode=TwoWay}"
TextWrapping="Wrap" />
code behind:
public MainPage()
{
this.InitializeComponent();
this.DataContext = myChangeCalc;
}
public ChangeCals myChangeCalc = new ChangeCals { Amountpaid = "111", GoodsCost = "222" };
Any way, the binding source should be an instance of your data model(ChangeCals class). Since you used {Binding} here, I didn't show sample of using {x:Bind}, if you want to learn more about {x:Bind}, you can refer to {x:Bind} markup extension. For more info about binding and x:Bind, you can refer to Data binding in depth.
How to bind xml to wpf treeview? I am using Prism mvvm pattern. I will prefer an IList for holding the data for looping.
I have tried http://geeklyeverafter.blogspot.com/2010/03/wpf-treeview-bound-to-xml-file.html and
http://www.blogs.intuidev.com/post/2009/12/28/xml_to_treeview.aspx
but nothing worked.
OK. It is The question is quite old now, but I think there is a simple way to bind XML to a TreeView. Maybe it is helpful for someone.
XAML:
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Elements}" x:Key="NodeTemplate">
<Grid>
<TextBlock Text="{Binding Path=Name}"/>
</Grid>
</HierarchicalDataTemplate>
</Window.Resources>
...
<TreeView x:Name="myTreeView" Grid.Column="0"
ItemsSource="{Binding Path=Root.Elements}"
ItemTemplate="{StaticResource ResourceKey=NodeTemplate}"
/>
In the code behind I just create a XDocument (System.Xml.linq) and bind this one to the DataContext of the TreeView. For example like this:
private XDocument _theXML;
public XDocument TheXML {
get => _theXML;
set => _theXML = value;
}
public MainWindow()
{
...
InitializeComponent();
DataContext = this;
TheXML = XDocument.Load(#"c:\file.xml");
myTreeView.DataContext = TheXML;
myTreeView.UpdateLayout();
}
That's it. The content of the XML file will be shown as a TreeView. If you like to see some more Details (Attributes, ...) you can refine the Template in the XAML code.
The way I've done it is to create a method that builds the tree view to a treeview property. Set the WPF treeview items binding to the items property of the treeview property in your class. Of course implementing INotifyPropertyChanged in your ViewModelBase is essential.
I would be happy to give an example, but I do not have access to the internet on my PC at the moment
I did see in the post and do agree that this is not the most proficient way . However since you are already using xml serialization, the parsing of xml is done, now you just have to use the data.
I think that if you were not going to serialize, then the links you posted would hold more validity in the methodology you are you are trying to achieve. But that is just IMO. I will update with some working code when I get the chance tomorrow, the idea of data binding directly to xml sounds fun.
In the meantime check this link out. It looks pretty strait forward.
http://social.msdn.microsoft.com/Forums/vstudio/en-US/cbdb2420-1403-436f-aa7f-b1e3b1acb398/binding-any-xml-document-to-wpf-treeview?forum=wpf
I would like to add pure XAML code into my xaml elements during runtime. Does anyone know how to do that? thank you.
I would like to do something like this: myGrid.innerXAML = stringXAMLcode
that would result to <grid name="myGrid">newgeneratedcodehere</grid>
in PHP you can print verbatim HTML code directly into the HTML file. Is this possible with c#?
if not, can anyone suggest a work-around?
thanks!
There are ways to do what you're asking here, as explained in this CodeProject Article:
Creating WPF Data Templates in Code: The Right Way
However, most of the time you really don't need that for daily operations.
If you're working with WPF, you really need to leave behind the traditional approach from other frameworks and embrace The WPF Mentality.
HTML (4, 5 or whatever) looks like a ridiculous joke when compared to the WPF implementation of XAML, therefore all the horrendous hacks you might be used to in HTML are completely unneeded in WPF, because the latter has a lot of built-in features that help you implement advanced UI capabilities in a really clean way.
WPF is heavily based on DataBinding and promotes a clear and well-defined separation between UI and Data.
For example, this would be what you would do to when you want to "show different pieces of UI" depending on the Data, by using a WPF feature called DataTemplates:
XAML:
<Window x:Class="MyWindow"
...
xmlns:local="clr-namespace:MyNamespace">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Person}">
<!-- this is the UI that will be used for Person -->
<TextBox Text="{Binding LastName}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Product}">
<!-- this is the UI that will be used for Product -->
<Grid Background="Red">
<TextBox Text="{Binding ProductName}"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<!-- the UI defined above will be placed here, inside the ContentPresenter -->
<ContentPresenter Content="{Binding Data}"/>
</Grid>
</Window>
Code Behind:
public class MyWindow
{
public MyWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
ViewModel:
public class MyViewModel
{
public DataObjectBase Data {get;set;} //INotifyPropertyChanged is required
}
Data Model:
public class DataObjectBase
{
//.. Whatever members you want to have in the base class for entities.
}
public class Person: DataObjectBase
{
public string LastName {get;set;}
}
public class Product: DataObjectBase
{
public string ProductName {get;set;}
}
Notice how I'm talking about my Data and Business Objects rather than worried about any hacks to manipulate the UI.
Also notice how defining the DataTemplates in XAML files that will get compiled by Visual Studio gives me compile-time checking of my XAML as opposed to putting it together in a string in procedural code, which of course doesn't have any kind of consistency checks.
I strongly suggest you read up on Rachel's answer (linked above) and related blog posts.
WPF Rocks
Why don't you add exactly the elements you want? Something like:
StackPanel p = new StackPanel();
Grid g = new Grid();
TextBlock bl = new TextBlock();
bl.Text = "This is a test";
g.addChildren(bl);
p.addChildren(g);
You can do this for all the elements that exist in the XAML.
Regards
You can use XamlReader to create the UIElement that you can set as child of content control or layout containers:
string myXamlString = "YOUR XAML THAT NEEDED TO BE INSERTED";
XmlReader myXmlReader = XmlReader.Create(myXamlString);
UIElement myElement = (UIElement)XamlReader.Load(myXmlReader);
myGrid.Children.Add(myElement );
I have a GridView that has several buttons. One of them is defined by the following template:
<DataTemplate x:Name="SubjectItemTemplate">
<Canvas Width="340" Height="170" VerticalAlignment="Top">
<Controls:ThreeImageButton HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0"
NormalStateImageSource="{Binding NormalImage}"
HoverStateImageSource="{Binding HoverImage}"
PressedStateImageSource="{Binding PressedImage}" Command="{Binding Path=NavigateToUnitsPage}"
CommandParameter="{Binding}" Canvas.Left="0" Canvas.Top="0">
</Controls:ThreeImageButton>
</Canvas>
</DataTemplate>
Now I have a custom control as you can see, called ThreeImageButton. The button works fine when I use it on its own. But when I have it in the DataTemplate it won't bind properties to the code behind.
Right now, I have
x:Name="MyThreeImageButton"
in the custom button definition. And I connect to the code-behind like this:
<TextBlock Text="{Binding ElementName=MyThreeImageButton, Path=NormalStateImageSource}"/>
(This is just a test to display the text, in the actual code I would assign an image source to another property that is referred to by an element).
Right now, nothing is displayed in the TextBlock. What is the correct binding syntax I'm supposed to use to reach my properties?
Thanks!
Edit: I am setting the variable in the InitializeComponent function and I am using SetValue on the DependencyProperty.
Edit: Let me add the following information to be more clear
Scenario I:
In DataTemplate for GridView:
<UserControl CustomParameter="Literal Text">
In UserControl:
<TextBlock Text="{Binding CustomParameter}">
in UserControl .cs: this.DataContext = this
works!
Scenario II:
In DataTemplate for GridView:
<UserControl CustomParameter="{Binding ValueFromDataItem">
In UserControl:
<TextBlock Text="{Binding CustomParameter}">
in UserControl .cs: this.DataContext = this
nope!
I see,
So setting up a two-way binding to a custom property in a user control can be tricky because a user control cannot bind to a CLR property. Not only that but setting the data context on a user control has an unexpected effect on the binding inside it.
You can solve these problems with a little slight of code. Basically back your CLR properties with dependency properties and set the data context on a child element instead of the root user control.
Take a look at this sample. Let's pretend you have the following MainPage. That MainPage will eventually use our custom user control. So let's set the stage.
Here's the code-behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.DataContext = new /* your view model */
{
Title = Guid.NewGuid().ToString(),
};
}
}
In the code above I am simulating a complex view model with a simple anonymous class. It would be silly for you to implement your own like this, but at the same time it is silly for me to build a simple sample with the complete scaffolding. I bring this up only so it does not confuse you - as it could look like I am suggesting this approach in prod.
Here's the XAML:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<local:MyUserControl Text="{Binding Title}" />
</Grid>
In the XAML above, there is absolutely nothing special. I already have reference to the user control in the local namespace and I simply declare it here.
Okay, now that we have a consumer of the control, it's worth pointing out that in testing developers can mistakenly think that their binding is working because they test with literal values. Literal values bind fine. It's binding from the underlying view model that hick-ups.
Let's say another thing, some developers tend to avoid dependency properties because the require a little more typing. People remember that [kbd]propdp[/kbd] is a handy Visual Studio snippet that stubs out a dependency property for you.
Take a look at this user control. It has two controls, a TextBox and a TextBlock which are there to demonstrate the OneWay and TwoWay functionality of this binding approach. We also implement INotifyPropertyChanged on the user control. For the most part, adding a view model in the case of a user control is overkill because the user control already acts like a view model. It's up to the developer, but it seems dumb to me.
Here's the code behind:
public sealed partial class MyUserControl : UserControl, INotifyPropertyChanged
{
public MyUserControl()
{
this.InitializeComponent();
}
// text property
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValueDp(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl), null);
// bindable
public event PropertyChangedEventHandler PropertyChanged;
void SetValueDp(DependencyProperty property, object value,
[System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
SetValue(property, value);
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In the ode above, I have create a "Text" property and backed it with a dependency property. For a matter of reuse I have also implemented SetValueDp() which could be used again and again if I had more than a single property. Even though this demo has but one, I wanted to include this because the repetitive logic should certainly be abstracted out like this.
Here's the XAML:
<Grid Background="Black" DataContext="{Binding ElementName=userControl}">
<StackPanel>
<TextBox Text="{Binding Text, Mode=TwoWay}"
MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
<TextBlock Text="{Binding Text}"
MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
</StackPanel>
</Grid>
In the XAML above, I do nothing special insofar as binding. The syntax simply binds to the Text property using the Mode appropriate to the control. Just like you would do normally. However, what's worth noticing is that the DataContext is NOT set on the user control. Instead, it is set on the Grid. As a point of fact, any control in the tree other than the user control could be used like this. Just don't set the data context of the user control.
That is it by the way.
I have tested it to make sure it works. Demonstrating both one and two way binding is pretty handy here. I might even turn this into a blog in case other developers want to find it and don't discover this question. Thanks for your question!
Best of luck!
As the comments alluded to, your DataTemplate is placing the datacontext of the items to whatever object you are adding to your list. This is not the same as the surrounding user control's data context. If you want to reference that datacontext's commands, do the following in the DataTemplate's bindings:
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.NormalImage}
What this is saying is to go out and find the user control ancestor and use its datacontext and then look for the NormalImage property. If you run into problems, check your output window for binding errors. It is very helpful in finding binding problems.
I have this code part:
<TextBlock
Margin="5,3,5,1" Foreground="White"
FontWeight="Bold" FontStyle="Italic" TextAlignment="Center"
Text="{Binding AntennaName}"/>
and in my viewmodel:
private string antennaName;
public string AntennaName
{
get { return antennaName; }
set { antennaName = value; OnPropertyChanged("AntennaName"); }
}
I checked and I can confirm that in my actual code the AntennaName property does change but the textblock does not.
Can anyone please explain why is this happening? I'm pretty new to the mvvm scene.
Try this -
<TextBlock Text="{Binding DataContext.AntennaName,
RelativeSource={RelativeSource FindAncestor,
AncestorType=UserControl}}"/>
The problem somewhere lies in the way you are setting the DataContext for your UserControl. Somehow, textBlock is not inheriting the DataContext from its parent(UserControl). So, explicitly asking for it might work.
Explanation
UI elements by default search for the Binding in its DataContext unless explicitly specified to look into some other place.
Also, in case you haven't set the DataContext for the control, it will inherit DataContext from its parent Control and look for the Binding property in it. In case the binding property is not found on the parent DataContext either, binding fails silently and all you will see is empty string.
You can always look for Binding failures in the output window. If you look in the output window, you will see your property AntennaName over there.
Refer - Data Binding Overview