WPF: Nested collection binding - binding

My application shows a question and possible answers on that question. Now I want to give the correct answer (specified in the "CorrectAnswer" property) a green color. Can someone help me? Thanks.
public class Exercise
{
public string QuestionText { get; set; }
public int CorrectAnswer { get; set; }
public Answer[] Answers { get; set; }
...
}
public class Answer
{
public string AnswerText { get; set; }
...
}
XAML:
<StackPanel Orientation="Vertical">
<Label Content="{Binding Path=QuestionText}"></Label>
<ItemsControl ItemsSource="{Binding Path=Answers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=AnswerText}"></Label>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>

If you have some idea on ValueConverter in WPF, better make use of that. That will give you a lot of flexibility and easy to implement. Please let me know, if you still have some doubt.

Related

In Xamarin Android, how can we implement a carousel view?

I am using xamarin android.
I have to display a horizontal scrollable list.
As I am a beginner to Xamarin Android, I am unable to find a proper solution.
I could not find a proper way yet.
I make a demo and it has three parts.
First, I create a Model class to define my datatype.
public class Photo
{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string Url { get; set; }
}
Second, I create a ViewModel class to handle the data.
public class MyViewModel
{
public ObservableCollection<Photo> Photos { get; set; }
public MyViewModel()
{
Photos = new ObservableCollection<Photo>();
Photos.Add(new Photo() { Name = "Name1", Details = "Details1", Location = "Location1" });
Photos.Add(new Photo() { Name = "Name2", Details = "Details2", Location = "Location2" });
Photos.Add(new Photo() { Name = "Name3", Details = "Details3", Location = "Location3" });
}
}
Third, I bind the ViewModel to the MainPage and present it by a CarouselView.
In the MainPage.xaml.cs file
public MainPage()
{
this.BindingContext = new MyViewModel();
InitializeComponent();
}
In the MainPage.xaml file
<CarouselView ItemsSource="{Binding Photos}">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="20"
HeightRequest="100"
WidthRequest="100"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="{Binding Name}" HorizontalOptions="Center" VerticalOptions="Center" FontSize="Large"></Label>
<Label Text="{Binding Details}" HorizontalOptions="Center" VerticalOptions="Center" FontSize="Large"></Label>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
For more information you can refer to the Xamarin.Forms CarouselView Layout.

Pass a child component as Parameter in Blazor

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>

How to set a binding to an element that was not instantiated in XAML code

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!

ASP.NET MVC view model binding: how to populate a collection of objects?

Until some days ago it was quite easy to manage model binding in my application. I had a view model, called PersonOfferDTO, containing a collection of PersonProductOfferDTO. (yes, I'm using the DTO as a view model because a view model in this case would be equal to the DTO). Here below a simplified version of PersonOfferDTO
public class PersonOfferDTO
{
[DataMember]
public Guid PersonOfferId { get; private set; }
[DataMember]
public ICollection<PersonProductOfferDTO> Offers { get; set; }
}
And here below a simplified version of PersonProductOfferDTO
public class PersonProductOfferDTO
{
[DataMember]
public Guid PersonProductOfferId { get; private set; }
[DataMember]
public Guid PersonOfferId { get; set; }
[DataMember]
public int Quantity { get; set; }
[DataMember]
public decimal UnitPrice { get; set; }
}
I was able to populate the ICollection thanks to the method shown below (HTML code).
<form method="POST" action="/Offers/AddNewPersonOffer">
<input name="PersonProductOffers.Index" value="myKey1" hidden>
<input name="PersonProductOffers[myKey1].Quantity">
<input name="PersonProductOffers[myKey1].UnitPrice">
<input name="PersonProductOffers.Index" value="myKey2" hidden>
<input name="PersonProductOffers[myKey2].Quantity">
<input name="PersonProductOffers[myKey2].UnitPrice">
</form>
But during the last days I have increased the depth of my objects tree, so now I have the following code.
public class PersonOfferDTO
{
[DataMember]
public Guid PersonOfferId { get; private set; }
[DataMember]
public ICollection<PersonOfferParagraphDTO> Paragraphs { get; set; }
}
[DataContract]
public class PersonOfferParagraphDTO
{
[DataMember]
public Guid PersonOfferParagraphId { get; set; }
[DataMember]
public ICollection<PersonProductOfferDTO> PersonProductOffers { get; set; }
}
As you can see there is now one further level between PersonOfferDTO and PersonProductOfferDTO, and I can't figure out how to perform a "multilevel binding": create a PersonOfferDTO with more PersonOfferParagraphDTO each one containing more PersonProductOfferDTO.
NOTE: I don't want to use an incremental index ([0] , [1], ....)... but a string (["myKey"])
EDIT
By request, I add the controller here below
public ActionResult AddNewPersonOffer(PersonOfferDTO offer)
{
if (!UserHasPermissions())
{
return PartialView("_forbidden");
}
var errors = OffersCRUD.AddNewPersonOffer(offer);
if(errors.Count() == 0)
{
return RedirectToAction("Index");
}
return PartialView("_errors", new ErrorsViewModel(errors));
}
If you want to populate them with your own keys, you can define your collections within your view model as a Dictionary<string, YOURCLASS>it accepts a non-integer index value.
Example view model with Dictionary:
public class ViewModelTest
{
public Dictionary<string, Class1> Values { get; set; }
}
Example class to be used in the dictionary collection:
public class Class1
{
public int MyProperty { get; set; }
public Dictionary <string, Class2> MoreValues { get; set; }
}
public class Class2
{
public int AnotherProperty { get; set; }
}
Here's a form that populates the values:
#using (Html.BeginForm())
{
<input type="text" name="Values[yourkey1].MyProperty" />
<input type="text" name="Values[yourkey1].MoreValues[anotherKey1].AnotherProperty" />
<input type="text" name="Values[yourkey2].MyProperty" />
<input type="text" name="Values[yourkey2].MoreValues[anotherKey2].AnotherProperty" />
<input type="submit" />
}
Instead of writing your input tags yourself, you can use the helper methods and enjoy intellisense, assuming that you have your view model defined within the view with the same structure defined in your action method:
#model ViewModelTest
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Values[yourkey1].MyProperty)
#Html.TextBoxFor(x => x.Values[yourkey1].MoreValues[anotherKey1].AnotherProperty)
#Html.TextBoxFor(x => x.Values[yourkey2].MyProperty)
#Html.TextBoxFor(x => x.Values[yourkey2].MoreValues[anotherKey2].AnotherProperty)
<input type="submit" />
}
You'll have to introduce a view model for this of course and not just get away with using your DTO ;).
PS: A DTO shouldn't be used as a domain model either, it's for transporting information around your layers.

What should I do to get the values of a listbox item in wpf c#?

I have a few images with some text, I need to get the image path with the relevant text in a listbox.
Browsing google I came across this sample class,
public class Img
{
public Img(string value, Image img) { Str = value; Image = img; }
public string Str { get; set; }
public Image Image { get; set; }
}
<ListBox x:Name="lstBox">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:Img}">
<StackPanel>
<TextBlock Margin="3" Text="{Binding Str}"/>
<ContentControl Margin="3" Content="{Binding Image}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
lstBox.Items.Add(new Img("Value", myImage));

Resources