use binds in viewmodels - c#

I am doing a project and in one xaml page I have some Textblock with bind like this
<PivotItem Header="Lista">
<ListView x:Name="List1" ItemsSource="{x:Bind ProdutoViewModel.Produtos}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="list:Produto">`
...
<StackPanel>
<TextBlock x:Name="nome" Text="{x:Bind Nome, Mode=OneWay}" />
<TextBlock Text="{x:Bind Preco, Mode=OneWay}" />
<TextBlock Text="{x:Bind Disponivel, Mode=OneWay}" />
<TextBlock Text="{x:Bind Fornecedor, Mode=OneWay}" />
<TextBlock Text="{x:Bind Categoria, Mode=OneWay}" />
<Image Source="Assets/mouse.png" />
<Image Source="Assets/teclado.png"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</PivotItem>
And then I have another pivot like this
<PivotItem>
<PivotItem Header="Carrinho">
<ListView x:Name="Cart" ItemsSource="{x:Bind EncomendaProdutoViewModel.EncomendaProdutos}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="list:EncomendaProduto">
<StackPanel>
<Button x:Name="pay" Content="Pagar" Click="Payment_click"/>
<TextBlock Text="{x:Bind Quantidade, Mode=OneWay}" />
<TextBlock Text="{x:Bind Preco, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</PivotItem>
How can I show the data from the first pivot into the second? I have a button on the first pivotitem for each product and when I press it, I want to add the data of that product to the second pivotitem.

Create an outer view-model, like this:
<Page.DataContext>
<vm:MasterViewModel x:Name="ViewModel" />
</Page.DataContext>
class MasterViewModel
{
public ProdutoViewModel ProdutoViewModel { get; set; }
public EncomendaProdutoViewModel EncomendaProdutoViewModel { get; set; }
}
Then bind to the Pivot like this:
<Pivot>
<PivotItem>
<ListView ItemsSource="{x:Bind ViewModel.ProdutoViewModel.Produtos}"
SelectedItem="{x:Bind ViewModel.SelectedItem, Mode=TwoWay}" />
</PivotItem>
<PivotItem>
<ListView ItemsSource="{x:Bind ViewModel.EncomendaProdutoViewModel.EncomendaProdutos}"
SelectedItem="{x:Bind ViewModel.EncomendaProdutoViewModelSelectedItem, Mode=TwoWay}" />
</PivotItem>
</Pivot>
Then, handle the selection in code-behind:
class MasterViewModel
{
public ProdutoViewModel ProdutoViewModel { get; set; }
public EncomendaProdutoViewModel EncomendaProdutoViewModel { get; set; }
Producto _ProdutoViewModel;
public Producto ProdutoViewModel
{
get { return _ProdutoViewModel; }
set {
_ProdutoViewModel = value;
EncomendaProdutoViewModel.EncomendaProdutos.Add(value);
}
}
}
I hope this makes sense.
Best of luck!

Related

WPF Binding Listbox into ListView (different Source / datacontext)

i have these two classes.
classes:
public class OuterList
{
public string Process { get; set; }
public OuterList(string _process)
{
Process = _process;
}
}
public class InnerList
{
public string Order { get; set; }
public string Product { get; set; }
public InnerList(string _order, string _product)
{
Order = _order;
Product = _product;
}
}
And i will get a Listbox in a ListView.
XAML:
<ListView x:Name="Container" ItemsSource="{Binding OuterList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="5" FontSize="24" FontFamily="Arial" Background="Red" Text="{Binding Process}"/>
<ListBox x:Name="Orders" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=DataContext.InnerList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Product}"/>
<TextBlock Text="{Binding Order}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code:
public partial class MainWindow : Window
{
ObservableCollection<OuterList> myContainers = new();
ObservableCollection<InnerList> myItems = new();
public MainWindow()
{
InitializeComponent();
myContainers.Add(new OuterList("Start"));
myContainers.Add(new OuterList("Middle"));
myContainers.Add(new OuterList("End"));
Container.ItemsSource = myContainers;
myItems.Add(new InnerList("34545","SD5"));
myItems.Add(new InnerList("45654", "SD5"));
myItems.Add(new InnerList("65775", "SD5"));
myItems.Add(new InnerList("78677", "SD5"));
myItems.Add(new InnerList("35887", "SD5"));
Orders.ItemsSource = myItems; //<- The name "Orders" does not exist in the current context.
}
}
All the Content of the OuterList will shown, but no Item from InnerList
How can i add Content from two different ItemSources? Or, what am I doing wrong?
Got an issue in Code: The name "Orders" does not exist in the current context.
Thanks for you Help!
Because your DataContext is incorrect.
Assuming the Grid that wraps both of them its DataContext contains Outer and Inner
You can do this:
<Grid>
<ListView x:Name="Container" ItemsSource="{Binding OuterList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="5" FontSize="24" FontFamily="Arial" Background="Red" Text="{Binding Process}"/>
<ListBox x:Name="Orders" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=DataContext.InnerList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Product}"/>
<TextBlock Text="{Binding Order}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

In WPF, adding UserControl C# object from ViewModel to View

I have a UserControl in ViewModel which is a Property in ViewModel. I will obtain this UserControl from some dll's.
private GraphicControl _graphicCtrl;
public GraphicControl GraphicCtrl
{
get { return _graphicCtrl; }
set
{
_graphicCtrl = value;
NotifyPropertyChanged();
}
}
In the above property, GraphicCtrl is nothing but a UserControl. I want to display this in my View (xaml). So how should I achieve this.?
Here is a very simple example how to separate this
public class MainViewModel : ReactiveObject
{
public MainViewModel()
{
Stuff = new ObservableCollection<object>
{
new Person { FirstName = "Jon", LastName="Doe", },
new Car { Brand = "Ford", Model = "Model T" },
};
}
public IEnumerable Stuff { get; }
[Reactive] public object SelectedStuff { get; set; }
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Car
{
public string Brand { get; set; }
public string Model { get; set; }
}
As you can see, no dependency to any controls or other UI related stuff.
Now the view where I decide how to present the data from the ViewModel
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox
ItemsSource="{Binding Stuff}"
SelectedItem="{Binding SelectedStuff}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:Car}">
<TextBlock>
<Run Text="{Binding Brand}" /><Run Text=" - " /><Run Text="{Binding Model}" />
</TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Person}">
<TextBlock>
<Run Text="{Binding FirstName}" /> <Run Text="{Binding LastName}" />
</TextBlock>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentControl
Grid.Column="1"
Content="{Binding SelectedStuff}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:Car}">
<local:CarControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Person}">
<local:PersonControl/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
the CarControl
<StackPanel>
<Label Content="Car" />
<Label Content="Brand" />
<TextBlock Text="{Binding Brand}" />
<Label Content="Model" />
<TextBlock Text="{Binding Model}" />
</StackPanel>
the PersonControl
<StackPanel>
<Label Content="Person" />
<Label Content="FirstName" />
<TextBlock Text="{Binding FirstName}" />
<Label Content="LastName" />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
and finally a screenshot
I want to display this in my View (xaml). So how should I achieve this.?
Short answer: Use a ContentControl and bind its Content property to the UserControl:
<ContentControl Content="{Binding GraphicCtrl}" />
As others have already mentioned, exposing a UserControl from a view model is not MVVM though.
You should rather expose a POCO data object called Graphic or something and then use a DataTemplate to map this type to a UserControl in the view:
<ContentControl Content="{Binding Graphic}">
<ContentControl.ContentTemplate>
<DataTemplate>
<local:GraphicControl />
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>

Add items to custom ListBox

I've this template of ListBoxItem that contains an Image and TextBlock. How to add an Item to this ListBox from code?
<ListBox Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding}" Width="16" />
<TextBlock Text="{Binding}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I am assuming you will want to have a class which has imagesource and text properties in the lines of
public class TestClass()
{
public string ImageSrc {get; set;}
public string DisplayText {get; set;}
}
Add the objects to your collection
listBox.Items.Add(new TestClass() { ImageSrc = "blahblah", DisplayTest = "Test Display Text" });
and so on
Then you can use xaml in the lines of
<ListBox Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding ImageSrc}" Width="16" />
<TextBlock Text="{Binding DisplayText}" Margin="5,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF Tabcontrol of Datagrids

I'm trying to create a databound Tabcontrol, where each TabItem contains a Datagrid, also databound.
My data structure is something like this:
public class Exercise
{
public Guid ExerciseID { get; protected set; }
public string ExerciseName { get; set; }
public List<Set> Sets { get; set; }
}
public class Set
{
public Guid SetID { get; protected set; }
public decimal Weight { get; set; }
public decimal Reps { get; set; }
public bool MaxEffort { get; set; }
}
I'm trying to bind a List<Exercise> to a TabControl, and the List<Set> for each Exercise to the DataGrid within each Tab, displaying the "Weight" and "Reps" properties in two columns. My current XAML code is below, with the relevant section labelled.
<Window x:Class="MyWorkouts.WorkoutViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WorkoutViewer" Height="424" Width="708"
x:Name="WorkoutDisplay">
<Grid DataContext="{DynamicResource WorkoutToDisplay}">
<Calendar SelectedDate="{Binding WorkoutDate}" Height="180" HorizontalAlignment="Left" Margin="8,12,0,0" Name="calendar1" VerticalAlignment="Top" Width="230" />
<StackPanel Height="94" HorizontalAlignment="Left" Margin="12,182,0,0" Name="spProperties" VerticalAlignment="Top" Width="238">
<StackPanel Height="30" Name="spProgram" Width="232" Orientation="Horizontal">
<Label Content="Workout Program:" Height="25" Name="lblProgram" Width="104" />
<TextBox Text="{Binding WorkoutProgram}" Height="25" Name="tbProgram" Width="120" />
</StackPanel>
<StackPanel Height="30" Name="spType" Width="232" Orientation="Horizontal">
<Label Content="Workout Type:" Height="25" Name="lblWorkoutType" Width="104" />
<TextBox Text="{Binding WorkoutType}" Height="25" Name="tbWorkoutType" Width="120" />
</StackPanel>
<StackPanel Height="30" Name="spVenue" Width="232" Orientation="Horizontal">
<Label Content="Workout Venue:" Height="25" Name="lblVenue" Width="104" />
<TextBox Text="{Binding WorkoutVenue}" Height="25" Name="tbVenue" Width="120" />
</StackPanel>
</StackPanel>
<TabControl Height="365" HorizontalAlignment="Left" Margin="260,10,0,0" Name="TCWorkoutView" VerticalAlignment="Top" Width="425">
<TabItem Header="Workout View" Name="TIView">
<StackPanel Height="335" HorizontalAlignment="Left" Name="spExercises" VerticalAlignment="Top" Width="410" Grid.ColumnSpan="2">
<ItemsControl ItemsSource="{Binding Exercises}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding ExerciseName}" BorderThickness="1" BorderBrush="DarkBlue">
<ItemsControl ItemsSource="{Binding Sets}" DisplayMemberPath="WeightForReps" BorderThickness="1" BorderBrush="Gray"/>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</TabItem>
<!--The below section is the one in question-->
<TabItem Header="Edit Workout">
<TabControl ItemsSource="{Binding Path=Exercises}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Path=Sets}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Weight" Binding="{Binding Path=Weight}"/>
<DataGridTextColumn Header="Reps" Binding="{Binding Path=Reps}"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</TabControl>
</TabItem>
</TabControl>
</Grid>
I've got as far as having the ExerciseName property correctly displayed in each Tab (with the correct number of tabs generated, but there's no datagrid at all, instead the Tab just says MyWorkouts.Exercise (MyWorkouts is the namespace).
For a bit of background, this is meant to be the "Edit" screen for a workout logging program, and I've got the display view working correctly with a stackpanel of expanders - I need whatever solution I have to be editable, and have the changes made in the datagrid reflected in the appropriate class objects - I hope to work this out myself, but if this approach won't work, please let me know!
EDIT: My full XAML code is now listed above
Needed to set the TabControl.ContentTemplate rather than the ItemsControl.ItemTemplate. Once I switched that, I could use the DisplayMemberPath property, and everything else worked!
The XAML code I needed was:
<TabControl ItemsSource="{Binding Path=Exercises}" DisplayMemberPath="ExerciseName">
<TabControl.ContentTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Path=Sets}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Weight" Binding="{Binding Path=Weight}"/>
<DataGridTextColumn Header="Reps" Binding="{Binding Path=Reps}"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>

Data Binding Help - WPF

I have those two classes:
class DownloadLink
{
public string Name { get; private set; }
public string Url { get; private set; }
//(...)
}
class DownloadGroup
{
public List<DownloadLink> Links { get; private set; }
//(...)
}
class Manager
{
public List<DownloadGroup> Groups { get; private set; }
}
Manager managerOBJ = new Manager();
I want to display this like that:
Everything will be in ListBox:
I wan to bind managerOBJ.Groups to that ListBox. - How to do it?
Than I want to create DataTamplate to display each group and all links in that group. - How to do it?
I want to do as much as possible from XAML
UPDATE:
This is what I got. It's not workig. List box is empty.
<ListBox DockPanel.Dock="Right" VerticalAlignment="Stretch" Width="500" HorizontalAlignment="Right" Background="#FFE1FFF5" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Visible" ItemsSource="{Binding Path=Groups}" Name="GroupsListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Height="30" VerticalAlignment="Top" Width="500" >
<Grid Height="Auto" Width="500">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="XX MB w XX plikach" HorizontalAlignment="Stretch" Margin="0"/>
</Grid>
<ListBox HorizontalAlignment="Stretch" Height="43" Margin="0,5,0,0" Width="Auto" VerticalAlignment="Top" ItemsSource="{Binding Path=Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and in code behid I have:
RapideoAccount = new Rapideo();
GroupsListBox.DataContext = RapideoAccount;
The whole manager is contained in a listbox, for each downloadgroup in the manager you add an itemscontrol that contains another items control with the links in it.
This can be done by using DataTemplates:
<ListBox Name="myGroups"
ItemsSource="{Binding Path=Groups}">
<!-- each List<DownloadGroup> in the manager: -->
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Links}">
<!-- each Link in the Downloadgroup -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=Url}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In code you would put:
Manager managerOBJ = new Manager();
myGroups.DataContext = managerOBJ;
define managerOBJ as a property in your viewmodel
binding viewmodel to your view.
binding ListBox itemssource to managerOBJ.Groups.
define DataTemplate inside ListBox to display each DownloadGroup.

Categories