Binding a code-behind defined property to a DataContext property in XAML? - c#

I'm trying to bind a property that was defined in Page code-behind to a ListView.DataContext property in XAML, but for some reason it's not working in the way that I thought, when I run the app the ListView.DataContext is not being set and remains null, can someone please help me with that?
I looked for some similar questions but most of them solve the problem by setting the DataContext manually in the code-behind, but I'd like to do that from XAML.
MainPage.xaml
<Page
x:Class="CustomControls.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CustomControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<ListView
DataContext="{Binding Path=MyMarket, RelativeSource={RelativeSource Mode=Self}}"
ItemsSource="{Binding Path=Products}"
Header="{Binding Path=Name}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Id}"/>
<TextBlock Text="{Binding Path=Description}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Page>
MainPage.xaml.cs
using System.Collections.ObjectModel;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace CustomControls
{
public sealed partial class MainPage : Page
{
public Market MyMarket { get; private set; }
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
this.MyMarket = new Market
{
Name = "My Market",
Products = new ObservableCollection<Product>
{
new Product { Id = 123, Description = "qwerty" },
new Product { Id = 234, Description = "wertyu" }
}
};
}
}
public class Product
{
public int Id { get; set; }
public string Description { get; set; }
}
public class Market
{
public string Name { get; set; }
public ObservableCollection<Product> Products { get; set; }
}
}

You have to bind to the page, so you have to do that at the very top of your XAML:
<Page
[..]
DataContext="{Binding MyMarket, RelativeSource={RelativeSource Self}}">
Then you should be able to hook into that like this:
<ListView
ItemsSource="{Binding Path=Products}"
Header="{Binding Path=Name}">
[..]
Now just switch the lines in your constructor so that your elements are already there before the page is built:
this.MyMarket = new Market
{
Name = "My Market",
Products = new ObservableCollection<Product>
{
new Product { Id = 123, Description = "qwerty" },
new Product { Id = 234, Description = "wertyu" }
}
};
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
You should consider using Viewmodel classes later on.

{RelativeSource Mode=Self} refers to the current element, in this case ListView, so it's not what you want. The easiest way is to give a name to the root element (the Page), for instance "root", and specify ElementName=root in your binding.

Related

WPF: How to bind data from a code behind variable to content in xaml

I cant bind the variable from code behind in my wpf radiobutton
Can anyone help me to display the values from the variables in the content from the radio button.
MainWindow.xaml:
<RadioButton GroupName="Preis" Grid.Row="10" Content="{Binding Name1}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="11" Content="{Binding Name2}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="12" Content="{Binding Name3}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="13" Content="{Binding Name4}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
<RadioButton GroupName="Preis" Grid.Row="14" Content="{Binding Name5}" FlowDirection="RightToLeft" HorizontalAlignment="Left"/>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Produkte produkte = new Produkte();
produkte.Name1 = "Handstaubsauger";
produkte.Name2 = "Fensterwascher";
produkte.Name3 = "Dampfreiniger";
produkte.Name4 = "Hochdruckreiniger";
produkte.Name5 = "Geschenkgutschein";
// Regex für Email
String regexEmail = #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
// Hier weitermachen
}
}
Produkte.cs
public class Produkte
{
public String Name1 { get; set; }
public String Name2 { get; set; }
public String Name3 { get; set; }
public String Name4 { get; set; }
public String Name5 { get; set; }
public Int16 Stimmen1;
public Int16 Stimmen2;
public Int16 Stimmen3;
public Int16 Stimmen4;
public Int16 Stimmen5;
}
public MainWindow()
{
InitializeComponent();
Produkte produkte = new Produkte();
produkte.Name1 = "Handstaubsauger";
produkte.Name2 = "Fensterwascher";
produkte.Name3 = "Dampfreiniger";
produkte.Name4 = "Hochdruckreiniger";
produkte.Name5 = "Geschenkgutschein";
// ADD THIS
DataContext = produkte;
// Regex für Email
String regexEmail = #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
// Hier weitermachen
}
Note that if you try to bind to Stimmen1, Stimmen2, etc. in your view, it will fail, because they are fields. They must have { get; } to be able to bind to them.
You really need to turn Produkte into a proper viewmodel with INotifyPropertyChanged etc., but this will get a read-only view working right now.
In your xaml within the Window tag on the top, you would need to define your DataContext. If it is your code behind it would be Self. Once you have the DataContext set, you will be able to access public properties for binding.
<Window x:Class="Account.Client.PotentialMisallocation.Controls.DisplayAndFilter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
You will need to expose a public property of type Product in your code behind:
public Product Product
{
get { return new Product() {Id = 1, Name = "James"}; }
}
Then in xaml, you would do sth like:
<Label x:Name="label" Content="{Binding Product.Id}" />
<Label x:Name="label1" Content="{Binding Product.Name}" />

Binding model from a view wpf c#

I'm trying to build a DTO to store the software configuration, but I'm stuck because my view is not sending the data to my ViewModel and also to my DTO.
I need to transfer 2 textbox and 3 combobox to my DTO, but using this code the values are always empty.
My ViewModel:
public class ViewModelProcessamentoArquivo : ViewModelBase
{
private PesquisaConfiguracao pesquisaConfiguracao;
public PesquisaConfiguracao PesquisaConfiguracao
{
get { return pesquisaConfiguracao; }
set
{
pesquisaConfiguracao = value;
base.OnPropertyChanged("PesquisaConfiguracao");
}
}
}
My DTO/Model
public class PesquisaConfiguracao
{
public string ArquivoOrigem { get; set; }
public string ArquivoDestino { get; set; }
public string TipoPesquisa { get; set; }
public string PesquisaVeicular { get; set; }
public string PesquisaCrediticia { get; set; }
}
And my View is like this.
<TextBox Name="txtBuscarArquivoOrigem" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Height="30" Margin="10, 0" Text="{Binding PesquisaConfiguracao.ArquivoOrigem}" />
<TextBox x:Name="txtBuscarArquivoDestino" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3" Height="30" Margin="10, 0" Text="{Binding PesquisaConfiguracao.ArquivoDestino}" IsEnabled="false" />
...
Do you guys know why it's happening? I've used something similar in my other project and worked just fine. Also if you have any other possibly way to fix this issue, please comment!
First UpdateSourceTrigger PropertyChanged, that way the target (view) will update your source object on every change:
<TextBox Name="txtBuscarArquivoOrigem" Height="30" Text="{Binding PesquisaConfiguracao.ArquivoOrigem, UpdateSourceTrigger=PropertyChanged}" />
Then implement in your source object the INotifyPropertyChange Interface on it's properties in order to update the view when the value has changed:
private string _arquivoOrigem;
public string ArquivoOrigem
{
get
{
return _arquivoOrigem;
}
set
{
_arquivoOrigem = value;
OnPropertyChanged("ArquivoOrigem");
}
}
Put a BreakPoint in the property setter and it will break there when you change the value in the view TextBox.
If it doesn't work for you probably forgot to set your DataContext to your ViewModel:
<Window x:Class="WpfApplication1.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"
mc:Ignorable="d"
Title="MainWindow"
DataContext="{StaticResource MainViewModel}">
Or did not initialize your source object:
public MainViewModel()
{
pesquisaConfiguracao = new PesquisaConfiguracao
{
ArquivoDestino = "aaa",
ArquivoOrigem = "bbb",
PesquisaCrediticia = "ccc",
PesquisaVeicular = "dddd",
TipoPesquisa = "eee"
};
}

Caliburn Micro - bind ListBox to property of objects in a collection

I'm having trouble with binding the ItemsSource of a listbox to a collection of objects and then displaying a property of those objects as the list items.
My XAML code:
<Window 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"
mc:Ignorable="d"
x:Class="CaliburnMicroBasic.ShellView"
d:DesignWidth="358" d:DesignHeight="351">
<Grid Width="300" Height="300" Background="LightBlue">
<ListBox ItemsSource="{Binding ListOfPeople}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
My ViewModel:
namespace CaliburnMicroBasic {
using Caliburn.Micro;
using System.Collections.ObjectModel;
using System.Windows;
public class ShellViewModel : Screen, IShell
{
public Person SelectedPerson{ get; private set; }
public ObservableCollection<Person> ListOfPeople{ get; private set; }
public ShellViewModel()
{
ListOfPeople = new ObservableCollection<Person>();
ListOfPeople.Add(new Person("Name 1"));
ListOfPeople.Add(new Person("Name 2"));
ListOfPeople.Add(new Person("Name 3"));
ListOfPeople.Add(new Person("Name 4"));
}
}
public class Person
{
public string PersonName { get; private set; }
public Person(string personName)
{
_personName = personName;
}
}
}
As you can see, I'm trying to have the listbox use Person.PersonName as the contents of each textblock in the listbox, but all I'm getting is four empty rows in the listbox. In other words, the listbox contains the correct number of items, but none of them are rendered correctly.
Can anyone see what I'm doing wrong?
You are never assigning anything to your PersonName property. Change your code to:
public Person(string personName)
{
this.PersonName = personName;
}
and remove your private field.

Items Template code-behind

Is there a way to access the containers generated for an itemscontrol's items?
For example,
Given an ItemsControl with an ItemTemplate as shown below, access the actual TextBlock within the DataTemplate generated for each item in the control. (not the object, but its associated textblock).
Views/MainPage.xaml:
<phone:PhoneApplicationPage
x:Class="PhoneApp1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:PhoneApp1.ViewModels"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls. Toolkit"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<phone:Pivot>
<phone:Pivot.Resources>
<vm:PersonViewModel x:Key="ViewModel"/>
</phone:Pivot.Resources>
<phone:PivotItem>
<phone:PivotItem.Header>
<TextBlock Text="Pivot"/>
</phone:PivotItem.Header>
<ItemsControl x:Name="People" DataContext="{StaticResource ViewModel}" ItemsSource="{Binding People}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock toolkit:SlideInEffect.LineIndex="{Binding PersonLineIndex}" Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</phone:PivotItem>
<phone:PivotItem>
<phone:PivotItem.Header>
<TextBlock Text="Empty Pivot"/>
</phone:PivotItem.Header>
</phone:PivotItem>
</phone:Pivot>
</phone:PhoneApplicationPage>
Views/MainPage.xaml.cs
using Microsoft.Phone.Controls;
namespace PhoneApp1
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
}
}
ViewModels/PersonViewModel.cs
using PhoneApp1.Models;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace PhoneApp1.ViewModels
{
public class PersonViewModel
{
public PersonViewModel()
{
People = new ObservableCollection<Person>
{
new Person { Name = "Joe" },
new Person { Name = "Jack" },
new Person { Name = "James" },
new Person { Name = "John" }
};
PersonLineIndex = new List<int>();
for (int i = 0; i < People.Count; i++)
{
PersonLineIndex.Add(i);
}
}
public ObservableCollection<Person> People { get; set; }
public List<int> PersonLineIndex { get; set; }
}
}
Models/Person.cs:
namespace PhoneApp1.Models
{
public class Person
{
public string Name { get; set; }
}
}
Why would I need this access? For example:
Try to set a different line index for each textblock. Without adding a "LineIndex" property to your Person (as that would violate MVVM).
I figured it out. You would access such ItemsControl's ItemContainerGenerator
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
People.Loaded += People_Loaded;
}
void People_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
for (int i = 0; i < People.Items.Count; i++)
{
var container = People.ItemContainerGenerator.ContainerFromIndex(i);
container.SetValue(SlideInEffect.LineIndexProperty, i);
}
}
}

Problem with MVVM. Dynamic list of grids

I don't know according to MVVM show data on control.
I have a collection of cars.
I want group their by type (eg. Sedan, Combi, Hatchback) and depends of number of types print grids.
So :
5 cars:
2 x sedan, 2 x Combi, 1 x sportcar.
So I want to print 3 grids.
How do it to be ok with MVVM.
Below is some sample code. If your lists of cars can change you should use ObservableCollections instead or implement INotifyPropertyChanged on your viewmodel.
XAML:
<Window x:Class="TestApp.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Path=CarTypes}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Key}" />
<ListBox ItemsSource="{Binding Path=Value}" DisplayMemberPath="Name" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</Window>
Code behind:
using System.Collections.Generic;
using System.Windows;
namespace TestApp
{
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
DataContext = new CarsVM();
}
}
public class CarsVM
{
public CarsVM()
{
CarTypes = new Dictionary<string, List<Car>>();
// You want to populate CarTypes from some model.
CarTypes["sedan"] = new List<Car>() {new Car("Honda Accord"), new Car("Toyota Camry")};
CarTypes["musclecar"] = new List<Car>() { new Car("Chevy Camaro"), new Car("Dodge Challenger") };
CarTypes["suv"] = new List<Car>() { new Car("Chevy Tahoe") };
}
public Dictionary<string, List<Car>> CarTypes { get; private set; }
}
public class Car
{
public Car(string name)
{
Name = name;
}
public string Name { get; set; }
}
}

Categories

Resources