I am trying to create my first app for Windows Phone 7.
I have a Detail View and the .cs class associated with the view.
In my view, I have :
<StackPanel Grid.Row="0" Grid.Column="0">
<TextBlock Name="textBlock1" Text="..."/>
</StackPanel>
In the .cs:
...
listAgences = new List<Agence>();
Agence agence1 = new Agence();
agence1.Name = "test";
agence1.Adresse = "test1";
...
listAgences.Add(agence1);
...
How do I get to have the Text in the textbox to be "test"?
I tried stuff like:
Text="{Binding Path=listAgences[0].Name}";
I know how to do this in ASP.NET, but here I'm quite lost.
Presuming that your datacontext class has a public property List<Agence> ListAgences { get; set; } then binding like that should work, though.
Related
I would like to do in Blazor something that I normally do in React: create a reusable component that internally uses other child components, with the ability to pass those child components as parameters. I need that to be able to treat child components as a dependency that can be injected on demand with any custom implementation that could be needed in different contexts.
Imagine, for instance, a TextBox.razor component that gives you the ability to pass a custom component to render the label as you want, as long as it implements an ILabel interface. I tried something like this but the syntax doesn't seem to be valid:
TextBox.razor
As you see from the screenshot, Blazor doesn't allow me to use the Parameter Label as a component. Any idea of how to achieve this?
You should be able to accomplish this with templated components.
Textbox.razor
#typeparam inputType
<div class="textbox">
#if(LabelTemplate!=null && TItem!=null)
#LabelTemplate(TItem)
<input type="text"/>
</div>
#code{
[Parameter]
public RenderFragment<inputType> LabelTemplate { get; set; }
[Parameter]
public inputType TItem { get; set; }
}
In the code above, you are specifying that the component accepts a type using #typeparam inputType and receive an object of that type as a parameter TItem.
You are also accepting a LabelTemplate which accepts an object of type inputType. To render this fragment, we call #LabelTemplate and pass in our TItem parameter.
Now lets look at how to use our templated component in a new component called PersonForm.razor
PersonForm.razor
<Textbox TItem="myPerson">
<LabelTemplate>
#context.Name
</LabelTemplate>
</Textbox>
<Textbox TItem="myPerson">
<LabelTemplate>
#context.PhoneNumber
</LabelTemplate>
</Textbox>
#code{
Person myPerson = new Person { Name = "Jane Doe", PhoneNumber = "999 999 9999" };
public class Person
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
}
I'm passing in my Person object to each Textbox component's TItem property, and accessing it in the LabelTemplate using the #context syntax.
This might seem confusing at first, so please read up on it here
Edited
It just depends on what you want to accomplish. With the Verbose syntax comes flexibility on the "implementation" side of the component. Instead of forcing an interface that might not work with a wide variety of models/classes, you are letting the implementation specify what to do.
If you want something less verbose/more rigid, you can do the following as well.
#implements ILabel
<div class="textbox">
<label>#Text</label>
<input type="text"/>
</div>
#code
{
[Parameter]
public string Text { get; set; }
}
ILabel.cs
public interface ILabel
{
string Text { get; set; }
}
I realize this is probably late, but I just struggled through this and found out it is SUPER easy! Thought I would put an easy answer out there for people looking.
Here is my OrdersNavigation.razor file (which I want to embed into a header):
<div class="nav-strip">
<NavLink href="orders">
<Icon Name="#Icons.Cart" /> List
</NavLink>
<NavLink href="orders/create">
<Icon Name="#Icons.Plus" /> Create
</NavLink>
</div>
Now here is my PageHeader.razor:
<div class="page-header">
<h3>#Title</h3>
#Navigation
</h3>
<hr />
#code {
[Parameter] public string Title { get; set; } = "[TITLE]";
[Parameter] public RenderFragment Navigation { get; set; }
}
Notice that the Navigation property is a RenderFragment - this is key. Now in my page, I can simply add it like this:
<PageHeader Title="Orders">
<Navigation>
<OrderNavigation />
</Navigation>
</PageHeader>
You see here that the Title parameter is entered like usual, but the Navigation parameter is entered as an element of PageHeader! Really, you can put anything in the tags and it will render where you have #Navigation.
Reference: https://blazor-university.com/templating-components-with-renderfragements/passing-data-to-a-renderfragement/
Took a shot at your example:
Label.razor
<label>#Text</label>
#code {
[Parameter] public RenderFragment Text { get; set; }
}
TextBox.razor
<div class="textbox">
<Label>
<Text>
<div>
Embedded label <br />
You can even drop components in here!
</div>
</Text>
</Label>
<input />
</div>
I´m relative new to coding and I´m working on a little project. This is what I´m trying to do:
I defined a class "MyObject" with two properties:
namespace WpfApplication2
{
public class MyObject
{
public string Property1 { get; set; }
public int Property2 { get; set; }
public MyObject() : this("", 0)
{
}
public MyObject(string p1, int p2)
{
Property1 = p1;
Property2 = p2;
}
}
}
...then instantiated two objects of this class in code:
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public List<MyObject> listOfMyObject { get; set; }
public MyObject myObj1 { get; set; }
public MyObject myObj2 { get; set; }
public MainWindow()
{
InitializeComponent();
listOfMyObject = new List<MyObject>();
myObj1 = new MyObject("Hello", 1);
myObj2 = new MyObject("Bye", 2);
listOfMyObject.Add(myObj1);
listOfMyObject.Add(myObj2);
}
}
}
Now I want to bind each property of the two MyObject objects to the Content Property of a Label object. So there should be four Label objects:
- Label1 should display the value of Property1 of myObj1
- Label2 should display the value of Property2 of myObj1
- Label3 should display the value of Property1 of myObj2
- Label4 should display the value of Property2 of myObj2
I tried it this way:
<Window x:Class="WpfApplication2.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:WpfApplication2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Name="mywin">
<Grid>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<StackPanel>
<Label Name="Label1" Content="{Binding ElementName=myObj1, Path=Property1}"/>
<Label Name="Label2" Content="{Binding ElementName=myObj1, Path=Property2}"/>
</StackPanel>
<StackPanel>
<Label Name="Label3" Content="{Binding ElementName=myObj2, Path=Property1}"/>
<Label Name="Label4" Content="{Binding ElementName=myObj2, Path=Property2}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
... but it doesn´t work. Please help me to understand how to use the Binding correctly!
Greetings
// Even if I already figured out how to solve my problem, I would be pleased, // if someone could answer to the question at the end of this post!
Okay, now I figured out (with a little help from a friend), how to fix my problem:
I set the DataContext property of the MainWindow object, that contained the Label objects to itself by doing this:
mywin.DataContext = this;
So the code looks like this now:
public partial class MainWindow : Window
{
public List<MyObject> listOfMyObject { get; set; }
public MyObject myObj1 { get; set; }
public MyObject myObj2 { get; set; }
public MainWindow()
{
InitializeComponent();
listOfMyObject = new List<MyObject>();
myObj1 = new MyObject("Hello", 1);
myObj2 = new MyObject("Bye", 2);
listOfMyObject.Add(myObj1);
listOfMyObject.Add(myObj2);
// I added this code
mywin.DataContext = this;
}
}
And then I set the binding to the Content property of the four Label objects by doing this:
<Label Name="Label1" Content="{Binding Path=myObj1.Property1}" />
So my whole XAML code looks like this now:
<Window x:Class="WpfApplication2.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:WpfApplication2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Name="mywin">
<Grid>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<StackPanel>
<Label Name="Label1" Content="{Binding Path=myObj1.Property1}" />
<Label Name="Label2" Content="{Binding Path=myObj1.Property2}" />
</StackPanel>
<StackPanel>
<Label Name="Label3" Content="{Binding Path=myObj2.Property1}" />
<Label Name="Label4" Content="{Binding Path=myObj2.Property2}" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
NEW Question:
Now I would like to understand, why it doesn´t work the way I tried in the first way...
<Label Name="Label1" Content="{Binding ElementName=myObj1, Path=Property1}"/>
... when this would work:
<Label Name="Label1" Content="{Binding ElementName=Label2, Path=Content}"/>
<Label Name="Label2" Content="Hello">
The XAML code, in which the Label objects are instantiated and the C# code, in which the MyObject objects are instantiated, are both partial classes that belong together. In addition to that the MyObject objects myObj1 and myObj2 are properties of this class. So I thought that the Label-Elements in the XAML code should "know" about the MyObject objects myObj1 and myObj2 and therefore be able to reference them as source elements in the ElementName property of the Binding object. Thinking this way, I thought I must only set the Path property of the Binding object to the Property which value the Label object should display.
Can you help me to understand, where my idea of Binding is wrong? Thank you!
I have a strange problem with bindings on a custom control. I created a custom toolbar:
public partial class TopToolbar
{
public static readonly BindableProperty BackCommandProperty =
BindableProperty.Create(nameof(BackCommand), typeof(ICommand), typeof(TopToolbar), propertyChanged: BackCommandChanged);
public ICommand BackCommand
{
get => (ICommand) GetValue(BackCommandProperty);
set => SetValue(BackCommandProperty, value);
}
public TopToolbar()
{
InitializeComponent();
}
// for debug purposes only
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
Debug.WriteLine(BindingContext);
}
// for debug purposes only
private static void BackCommandChanged(BindableObject bindable, object oldvalue, object newvalue)
{
Debug.WriteLine($"old: {oldvalue}, new: {newvalue}");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Core.Controls.TopToolbar"
x:Name="TopToolbarView"
BindingContext="{x:Reference TopToolbarView}"
Orientation="Vertical">
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
<Image Source="{StaticResource Image.Toolbar.LeftArrow}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BackCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
I use it on a page in this way:
<pages:ContentPage.Content>
<StackLayout BackgroundColor="{StaticResource LightGrayColor}"
Spacing="0"
Padding="0">
<controls:TopToolbar Title="Master Data" BackCommand="{Binding MyBackCommand}" />
BindingContext of the page is a view model:
public class MyCustomersPageModel
{
public RelayCommand MyBackCommand { get; set; }
public MyCustomersPageModel()
{
MyBackCommand = // command creation;
}
}
From the debugging I know that BindingContext of a control is set (OnBindingContextChanged called) properly to itself (TopToolbar object) twice - first time when there's no child views and second time after they are added. I've checked that BindingContext is correctly propagated in all child controls.
Unfortunately the BackCommand is not bind at all. The setter of the TopToolbar.BackCommand is not called even once.
Interestingly when I replace setting the BindingContext on a control to setting the Souce directly in bindings everything works fine:
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Core.Controls.TopToolbar"
x:Name="TopToolbarView"
Orientation="Vertical">
<StackLayout Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
<Image Source="{StaticResource Image.Toolbar.LeftArrow}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference TopToolbarView}, Path=BackCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
Any clue what I do wrong?
It is working as expected. I would recommend using Source.
In first case, when you set BindingContext on TopToolbar to itself, then I would imagine this would be the sequence of events:
Custom control is constructed, BindingContext is assigned to self through reference.
Page instance is created, control is added to it.
When page's BindingContext is set, through power of property inheritance, all it's child controls' BindingContext is updated.
At this point your custom control's BindingContext is still referencing itself as value-propagation doesn't override manually set context.
Therefore, binding <controls:TopToolbar BackCommand="{Binding MyBackCommand}" fails, as this binding will try to look for MyBackCommand on it's binding-context which is TopToolbar.
But, in second case, when you specify binding Source as TopToolbar on Tapped command, then this should be the sequence of events:
Custom control is constructed, BindingContext is null.
Page instance is created, control is added to it.
When page's BindingContext is set, through power of property inheritance, all it's child controls' BindingContext is updated, including your custom control.
At this point your custom control's BindingContext is now referencing MyCustomersPageModel. So binding in <controls:TopToolbar BackCommand="{Binding MyBackCommand}" is appropriately set.
Now the Tapped binding doesn't care about BindingContext as it's source is explicitly specified, which is parent control TopToolbar - whose BackCommand in turn is bound to the view model's command. Hence, the view-model command is now bound to gesture-recognizer's Tapped command. And it works!
So I have a list of objects containing a name and number bound to a listbox in XAML. The listbox displays the number fine, but I want it to call the phone number using phonecall on click. Here is the onlick code:
private void taxiListItem_Click(object sender, RoutedEventArgs e)
{
Microsoft.Phone.Tasks.PhoneCallTask phonecall = new Microsoft.Phone.Tasks.PhoneCallTask();
phonecall.PhoneNumber = "213";
phonecall.Show();
}
and here is where I define the TaxiCompany object that populates the list.
public class TaxiCompany {
public String CoName { get; set; }
public String Phone { get; set; }
public TaxiCompany(String coname, String phone) {
this.CoName = coname;
this.Phone = phone;
}
}
The phone call works fine when I hardcode the number . Now, when I set phonecall.Phonenumber = sender.getPhone() or e.Phone() or any variant of the two, its marked as an undefined method. Am I doing something fundamentally wrong here? I assume object sender or e is the list item being clicked on.
Note: the listbox in the XAML displays both the phone number and address just fine
<Button Click="taxiListItem_Click" Width ="436" Height="120">
<Button.Content>
<StackPanel Orientation="Vertical" Height=" 80">
<StackPanel Orientation="Horizontal" Height="40" Width="436">
<TextBlock Width="436" FontSize="30" Text= "{Binding CoName}" Height="40"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="40" Width="436">
<TextBlock Name ="PhoneNo" Width="300" FontSize="22" Text= "{Binding Phone}" Height="40"/>
</StackPanel>
</StackPanel>
</Button.Content>
</Button>
First time working with C# / Silverlight so any help would be apprecaited.
Try this. The listbox shows the taxi companies and selecting an item in the list causes the phone numbe rot try and be dialed.
Notice that it's not necessary to add buttons to the list and that it's necessary to cast the variables passed to the selection event. (Could also cast the sender to a listbox and then cast the selected item.)
xaml:
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding TaxiCompanies}" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Height=" 80">
<TextBlock Width="436" FontSize="30" Text= "{Binding CoName}" Height="40"/>
<TextBlock Name ="PhoneNo" Width="300" FontSize="22" Text= "{Binding Phone}" Height="40"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
cs:
// class used for example. Another name would be more appropriate
public class ViewModel
{
public ObservableCollection<TaxiCompany> TaxiCompanies { get; private set; }
public ViewModel()
{
TaxiCompanies = new ObservableCollection<TaxiCompany>();
TaxiCompanies.Add(new TaxiCompany("AAA Cabs", "123-456-789"));
TaxiCompanies.Add(new TaxiCompany("BBB Taxis", "111234329"));
TaxiCompanies.Add(new TaxiCompany("CCC Cars", "98765432"));
}
}
public MainPage()
{
InitializeComponent();
// Set the data context of the listbox control to the sample data
DataContext = new ViewModel();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var phonecall = new PhoneCallTask();
phonecall.PhoneNumber = ((TaxiCompany)(((object[])(e.AddedItems))[0])).Phone;
phonecall.Show();
// Reset selected index to -1 (no selection)
MainListBox.SelectedIndex = -1;
}
The combobox items are taken from one table, one field on which binding is made. After I saved in the database the selected item in another table, I want that the selected item to be the one which was saved. But the selected item is lost. So, my question is: can I bind the combobox to two DataContexts or maybe another solution ?.
To give an example to be more clear: the combobox items are predefined values taken from a datasource and the value selected must be saved and shown on the interface. So, from what I can see must be a binding to the predefined values and also a binding to the value saved to make a connection to the selected item.
Any suggestion?
Ioana, I don't seem to get what you're aiming at..
if you take this xaml:
<Window x:Class="WpfApplication4.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">
<StackPanel>
<TextBox Text="{Binding Path=SelectedText, Mode=TwoWay}"
Width="200"/>
<ComboBox Width="200"
VerticalAlignment="Center"
HorizontalAlignment="Center"
SelectedItem="{Binding Path=SelectedText, Mode=TwoWay}"
ItemsSource="{Binding Path=Texts, Mode=OneWay}">
</ComboBox>
</StackPanel>
</Window>
and this codebehind:
public partial class Window1 : INotifyPropertyChanged
{
public Window1()
{
InitializeComponent();
this.Texts = new List<string>(new[] {"foo","bar"});
this.DataContext = this;
}
private ObservableCollection<string> texts;
public ObservableCollection<string> Texts
{
get
{
return texts;
}
set
{
texts = value;
if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("Texts"));
}
}
private string selectedText;
public string SelectedText
{
get
{
return selectedText;
}
set
{
selectedText = value;
if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("SelectedText"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
You do have the Items and the selectedValue databound.
Notice the INotifyPropertyChanged.
Is this what you're trying to achieve ?