C# WPF ListView control - Problem with binding data - c#

I'm having some trouble binding data to a ListView control. I watched many tutorials where it seems like they did it the way I did here with either binding to a collection or a class that had a collection of items.
When I add the cars in this example nothing is added to the listview control. Anything obvious I have missed here? I have checked that the cars are added to the collection during runtime.
The car class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CarClasses
{
internal class Car
{
string _brand = "";
string _model = "";
public Car(string brand, string model)
{
_brand = brand;
_model = model;
}
public string Brand
{
get { return _brand; }
set { _brand = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
}
}
MainWindow.xaml:
<Window x:Class="GridViewListView.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:GridViewListView"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="600">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="7*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView x:Name="lvCarList" ItemsSource="{Binding CarCollection }" Grid.Column="2" Width="200" Height="250" SelectionMode="Single" BorderThickness="3" BorderBrush="AliceBlue">
<ListView.Style>
<Style/>
</ListView.Style>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding Brand}"></Label>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding Model}"></Label>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Grid.Column="0">
<TextBlock Text="Brand" Margin="10,10,0,0"></TextBlock>
<TextBlock Text="Model" Margin="10,10,0,0"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" Margin="0,0,0,0">
<TextBox Name="txtBrand" HorizontalAlignment="Left" Width="100" Margin="10,10,0,0"></TextBox>
<TextBox Name="txtModel" HorizontalAlignment="Left" Width="100" Margin="10,10,0,0"></TextBox>
<Button Name="btnAdd" Content="Add" Margin="10, 10,10,10" Click="btnAdd_Click"></Button>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CarClasses;
namespace GridViewListView
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public partial class MainWindow : Window
{
List<Car> CarCollection = new List<Car>();
public MainWindow()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
Car newCar = new Car(txtBrand.Text, txtModel.Text);
CarCollection.Add(newCar);
txtBrand.Text = "";
txtModel.Text = "";
}
}
}

You should/need to specify the DataContext.
And you need to make the Car's collection a public property. It's currently a field.
And also it should be an ObservableCollection, because it's changed at runtime and changes should be displayed in the UI automatically.
public partial class MainWindow : Window
{
public ObservableCollection<Car> CarCollection { get; } = new ObservableCollection<Car>();
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
Car newCar = new Car(txtBrand.Text, txtModel.Text);
CarCollection.Add(newCar);
txtBrand.Text = "";
txtModel.Text = "";
}
}

Related

ViewModel issue

I need pop up a window which takes time. The button is in Pressed state until the new window is opened. Hence I want to add a wait indicator over the UI window after I click the button and before the the window opens. The code of ViewModel is correct because I referred to a sample code. But why there is no response after I click the button.
The project file URL
https://supportcenter.devexpress.com/attachment/file/5268961b-ce35-4e40-b7c1-e33bffab902b
MainWindow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DevExpress.Xpf.Core;
namespace WaitIndicatorDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : DXWindow
{
public MainWindow()
{
InitializeComponent();
vm = new MainVM();
DataContext = vm;
}
MainVM vm;
private void buttonShow_Click(object sender, RoutedEventArgs e)
{
vm.IsBusy = !vm.IsBusy;
}
}
}
ViewMode:
using DevExpress.Mvvm;
namespace WaitIndicatorDemo
{
public class MainVM
{
private readonly ISplashScreenService _waitIndicatorService;
public virtual bool IsBusy { get; set; }
public MainVM()
{
_waitIndicatorService =
ServiceContainer.Default.GetService<ISplashScreenService>("WaitIndicatorService");
}
protected void OnIsBusyChanged()
{
if (IsBusy)
_waitIndicatorService.ShowSplashScreen();
else
_waitIndicatorService.HideSplashScreen();
}
}
}
Below is the XAML, the comment ones are the original sample code. The checkbox bind to IsBusy. The indicator pop up when the checkbox is checked. I now want to pop up after press the button.
<dx:DXWindow x:Class="WaitIndicatorDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:waitIndicatorDemo="clr-namespace:WaitIndicatorDemo"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
WindowStartupLocation="CenterScreen" SnapsToDevicePixels="True"
Title="MainWindow" Height="350" Width="525">
<!--DataContext="{dxmvvm:ViewModelSource Type=waitIndicatorDemo:MainVM}"-->
<!--Title="MainWindow" Height="350" Width="525">-->
<Grid Margin="10">
<!--<dxe:CheckEdit Content="Is Busy" IsChecked="{Binding IsBusy}"
VerticalAlignment="Top" HorizontalAlignment="Left" />
<Button Content="Button1" IsEnabled ="{Binding IsBusy, Converter={dxmvvm:BooleanNegationConverter}}"
VerticalAlignment="Top" HorizontalAlignment="Center" Click="Button_Click"/>
<Button Content="Button2" IsEnabled="{Binding IsBusy, Converter={dxmvvm:BooleanNegationConverter}}"
VerticalAlignment="Top" HorizontalAlignment="Right"/>-->
<Button x:Name="buttonShow" Content="Show" HorizontalAlignment="Left" Height="35" Margin="50,70,0,0" VerticalAlignment="Top" Width="75" Click="buttonShow_Click" />
</Grid>
</dx:DXWindow>
You have a few mistakes in your code sample :
1- The method OnIsBusyChanged in your ViewModel is never called.
2- Your XAML doesn't declare any ISplashScreenService object in the Window behaviors, like a DXSplashScreenService for instance.
Here's how you can fix both of those issues.
First, fix the ViewModel.
public class MainVM
{
private readonly ISplashScreenService _waitIndicatorService;
private bool _isBusy;
public virtual bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
OnIsBusyChanged();
}
}
public MainVM()
{
_waitIndicatorService =
ServiceContainer.Default.GetService<ISplashScreenService>("WaitIndicatorService");
}
protected void OnIsBusyChanged()
{
_waitIndicatorService.SetSplashScreenState("Doing some work...");
if (IsBusy)
_waitIndicatorService.ShowSplashScreen();
else
_waitIndicatorService.HideSplashScreen();
}
}
Then, your XAML.
<dx:DXWindow x:Class="WaitIndicatorDemo.MainWindow"
<!-- ... -->
Title="MainWindow" Height="350" Width="525">
<dxmvvm:Interaction.Behaviors>
<dx:DXSplashScreenService x:Name="WaitIndicatorService">
<dx:DXSplashScreenService.ViewTemplate>
<DataTemplate>
<Grid>
<Border Background="LightGray" CornerRadius="5">
<Border BorderBrush="#FF0072C6" BorderThickness="1" Margin="15" CornerRadius="5">
<Grid>
<ProgressBar BorderThickness="0" Value="{Binding Progress}" Maximum="{Binding MaxProgress}" IsIndeterminate="{Binding IsIndeterminate}" Height="12" />
<TextBlock Text="{Binding State, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</Border>
</Grid>
</DataTemplate>
</dx:DXSplashScreenService.ViewTemplate>
</dx:DXSplashScreenService>
</dxmvvm:Interaction.Behaviors>
<Grid Margin="10">
<!-- ... -->
</Grid>
</dx:DXWindow>
This code was mainly taken from the How to: Use DxSplashScreenService sample.

How to stop Label from stacking in wpf

I am creating a program where if you click the button it adds a new label. However the problem is that when you click the add button the label keeps getting stack on top of eachother instead of being a list
Here is the code
c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace firstwpfapp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void addTask(object sender, RoutedEventArgs e)
{
String val = input.ToString();
Label todo = new Label();
todo.Content = val;
List.Children.Add(todo);
}
}
}
xaml
...
<Window x:Class="firstwpfapp.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:firstwpfapp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="-120,-142,0,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="451*"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="Wrapper"Background="LightGray" Orientation="Horizontal"></StackPanel>
<TextBox x:Name="input" Grid.Column="2" HorizontalAlignment="Left" Height="31" Margin="106,198,0,0" TextWrapping="Wrap" Text="Enter here" VerticalAlignment="Top" Width="166"/>
<Button Content="Button" Grid.Column="2" HorizontalAlignment="Left" Margin="106,234,0,0" VerticalAlignment="Top" Width="166" Height="26" Click="addTask"/>
<Grid x:Name="List" Grid.Column="2" HorizontalAlignment="Left" Height="391" Margin="507,160,0,0" VerticalAlignment="Top" Width="385"/>
</Grid>
</Window>
the list keeps getting stack on top of another each time the button is pressed
You can go ahead and add your items to a ListView which will stack the items for you as well as include an ItemSource that we can bind to so it will create the rows for each new ToDo item for you:
Note: I have not tested the below; I'm on my Macbook.
Instead of your Wrapper StackLayout, replace it with:
<ListView Name="Wrapper" Grid.Row="0" Grid.ColumnSpan="3" ItemsSource="{Binding Tasks}" />
Now, create a new file called Task.cs which we will use when creating a new type of Task (add the below to the Task.cs file):
public class Task { public string task { get; set;} }
Have your MainWindow inherit from the INotifyPropertyChanged interface INotifyPropertyChanged
public partial class MainWindow : Window, INotifyPropertyChanged
Now update the rest of your code behind of MainWindow to:
private ObservableCollection<Task> _tasks;
//Tasks will store all of the tasks of type Task that we add to it
//as well as be bound to our ListView that will display whatever we add to our Tasks
public ObservableCollection<Task> Tasks
{
get
{
return _tasks;
}
set
{
if (value != _tasks)
{
_tasks = value;
OnPropertyChanged("Tasks");
}
}
}
//Here we implement OnPropertyChanged so our ObservableCollection can be notified
//whenever we have a new task added to or removed from Tasks (this is created when we implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
//Create a new Task and add it to our Tasks any time the addTask button is clicked
private void addTask(object sender, RoutedEventArgs e)
{
Tasks.Add(new Task(input.Text));
}
Replace the Grid
<Grid x:Name="List" Grid.Column="2" HorizontalAlignment="Left" Height="391" Margin="507,160,0,0" VerticalAlignment="Top" Width="385"/>
with a StackPanel:
<StackPanel x:Name="List" Grid.Column="2" HorizontalAlignment="Left" Height="391" Margin="507,160,0,0" VerticalAlignment="Top" Width="385"/>
Adding child elements to a grid stacks them on top of each other (as you have noticed)
A StackPanel adds new child elements below (or after) the previous child element.
Try this ...................
XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Center"
Orientation="Horizontal"
Margin="0,50,0,0">
<TextBox Name="Input"
Width="300"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<Button Name="AddBtn"
Content="Add"
Margin="20,0,0,0"
VerticalAlignment="Center"
Width="100"
Click="AddBtn_Click"/>
</StackPanel>
<ListView Name="ItemListView"
ItemsSource="{Binding Path=LabelItems, Mode=OneWay}"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="20"/>
</Grid>
C# code:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private ObservableCollection<string> _labels = new ObservableCollection<string>();
public ObservableCollection<string> LabelItems
{
get { return _labels; }
set { _labels = value; RaisePropertyChanged(); }
}
private void AddBtn_Click(object sender, RoutedEventArgs e)
{
if(Input.Text != "" && Input.Text != null)
{
LabelItems.Add(Input.Text);
}
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged([CallerMemberName]string name = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}

C# WPF application using data binding, data templates and observable collection

I am making a program in C# WPF using data binding, data templates and observable collection. I am basing my application on the Data Binding Demo from http://msdn.microsoft.com/en-us/library/vstudio/ms771319(v=vs.90).aspx. For some reason I cannot make my program display any data from binding. Debugging tells me that my Records class collection works but on this line:
records_collection_db = (CollectionViewSource)(this.Resources["records_collection_db"]);
my 'records_collection_db' variable in null whereas it should be holding some data. I suspect that that my CollectionViewSource in xaml line is set incorrectly but I don't really know how to fix it. It is my first program in WPF and so I don't have much experience on the subject. At this moment the only visible difference between my code and the one from sample is that my initial window is... a where in the demo it an
Code (or at least shortened version of it):
Record class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApplication1
{
public class Record : INotifyPropertyChanged
{
private int Lp;
private string group;
public event PropertyChangedEventHandler PropertyChanged;
public int _Lp
{
get { return this.Lp; }
set { this.Lp = value; OnPropertyChanged("_Lp"); }
}
public string _group
{
get { return this.group; }
set { this.group = value; OnPropertyChanged("_group"); }
}
public Record(int Lp, string group)
{
this.Lp = Lp;
this.group = group;
}
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
Initial window
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Configuration;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var newWindow1 = new Audyt_window();
newWindow1.Show();
}
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:WpfApplication1"
xmlns:System="clr-namespace:System;assembly=Mscorlib"
Title="MainWindow" Height="350" Width="525"
WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<Style x:Key="text_style" TargetType="TextBlock">
<Setter Property="Foreground" Value="#333333" />
</Style>
</Window.Resources>
<Grid>
<Button Content="Start" HorizontalAlignment="Left" Margin="36,36,0,0" VerticalAlignment="Top" Width="178" Height="93" Click="Button_Click"/>
<Button Content="Zamknij" HorizontalAlignment="Left" Margin="202,223,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button Content="Rekordy" HorizontalAlignment="Left" Margin="318,56,0,0" VerticalAlignment="Top" Width="108" Height="52" Click="Button_Click_2" />
<Button Content="Dodaj" HorizontalAlignment="Left" Margin="351,157,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_3"/>
</Grid>
</Window>
Operational window
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ComponentModel;
namespace WpfApplication1
{
public partial class Audyt_window : Window
{
CollectionViewSource records_collection;
private ObservableCollection<Record> records = new ObservableCollection<Record>();
public ObservableCollection<Record> Records
{
get { return this.records; }
set { this.records = value; }
}
public Audyt_window()
{
load_temp_data();
InitializeComponent();
records_collection = (CollectionViewSource)(this.Resources["records_collection"]);
}
private void load_temp_data()
{
Record rek1 = new Record(601, "Gr1", "Pro1", "Pyt1", 600001, "Kat1", false, false);
Record rek2 = new Record(602, "Gr2", "Pro2", "Pyt2", 600002, "Kat2", false, false);
Record rek3 = new Record(603, "Gr3", "Pro3", "Pyt3", 600003, "Kat3", false, false);
this.Records.Add(rek1);
this.Records.Add(rek2);
this.Records.Add(rek3);
}
}
}
<Window x:Class="WpfApplication1.Audyt_window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Audyt"
xmlns:src="clr-namespace:WpfApplication1"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<CollectionViewSource Source="{Binding Source={x:Static Application.Current}, Path=Records}" x:Key="records_collection" />
<Style x:Key="text_style" TargetType="TextBlock">
<Setter Property="Foreground" Value="#333333" />
</Style>
<DataTemplate x:Key="Records_Template" DataType="{x:Type src:Record}">
<Border BorderThickness="2" BorderBrush="Navy" Padding="7" Name="Record_List_Border" Margin="3" Width="345">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Background="Aqua" Grid.Row="0" Grid.Column="0"
Name="textblock_Lp"
Style="{StaticResource text_style}"
Text="Lp: "
>
</TextBlock>
<TextBlock Background="Azure" Grid.Row="0" Grid.Column="1"
Name="datablock_Lp"
Style="{StaticResource text_style}"
Text="{Binding Path=_Lp}"
>
</TextBlock>
<TextBlock Background="Aqua" Grid.Row="0" Grid.Column="2"
Name="datablock_group"
Style="{StaticResource text_style}"
Text="{Binding Path=_group}"
>
</TextBlock>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Border Padding="10">
<Grid>
<ListBox Name="Hits_View_List" HorizontalAlignment="Left" VerticalAlignment="Top"
Height="525" Width="400" Margin="420,0,0,0"
BorderThickness="2" BorderBrush="DimGray"
ItemsSource="{Binding Source={StaticResource records_collection}}"
>
</ListBox>
</Grid>
</Border>
</Window>
In your Audyt_window you set the source of your binding of the CollectionViewSource to {x:Static Application.Current}, but the Records ObservableCollection is declared inside your Audyt_window
Change:
<CollectionViewSource Source="{Binding Source={x:Static Application.Current}, Path=Records}" x:Key="records_collection" />
To
<CollectionViewSource Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=Records}" x:Key="records_collection" />
And it should work I think.
you Name your collectionviewsource
x:Key="records_collection"
and you are searching for records_collection_db... that cant match
records_collection_db = (CollectionViewSource)(this.Resources["records_collection_db"]);
Change the Key or Change the string to the right name

Deserialization c# object and passing values in windows phone 8

I need to ask you guys about after deserialization, the process is okay but I need to know how could I print these values to the screen?
Here is my example code it is working on Windows Phone 8 environment.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using JsonSample.Resources;
using Newtonsoft.Json;
namespace JsonSample
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var rootObject = JsonConvert.DeserializeObject<RootObject>(e.Result);
// tbl_result.Text = rootObject;
// Console.WriteLine(rootObject);
// Use The rootObject
}
//This event of button placed in grid
private void btn_Parse_Click(object sender, RoutedEventArgs e)
{
//WebClient for pinging my api
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += webClient_DownloadStringCompleted;
webClient.DownloadStringAsync(new Uri("http://echo.jsontest.com/id/4456482/type/ggfd"));
}
}
}
Here is MainPage XAML
<phone:PhoneApplicationPage
x:Class="JsonSample.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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="JSON PARSING" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="lets parse" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Button x:Name="btn_Parse" Click="btn_Parse_Click" Content="Show me parsed data!" HorizontalAlignment="Left" Margin="77,28,0,0" VerticalAlignment="Top" Width="306"/>
<TextBlock x:Name="tbl_result" HorizontalAlignment="Left" Margin="39,100,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="376" Width="378" FontSize="24" Foreground="#FFFFF300"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
RootObject.cs here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JsonSample
{
public class RootObject
{
public int id { get; set; }
public string type { get; set; }
}
}
Try this :
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var rootObject = JsonConvert.DeserializeObject<RootObject>(e.Result) as RootObject;
tbl_result.Text = rootObject.type;
}

WPF User Control - Two way binding doesn't work

I have made a UserControl with a DependencyProperty and I would like to bind 2 way. But somehow this doesn't work. The "City"-property never gets set in the AddressViewModel when the property changes.
This is my UserControl:
XAML:
<UserControl x:Class="EasyInvoice.UI.CityPicker"
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"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="300"
DataContext="{Binding CityList, Source={StaticResource Locator}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox IsReadOnly="True" Margin="3" Text="{Binding SelectedCity.PostalCode, Mode=OneWay}" Background="#EEE" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
<ComboBox Margin="3" Grid.Column="1" ItemsSource="{Binding Path=Cities}" DisplayMemberPath="CityName" SelectedItem="{Binding SelectedCity}"/>
</Grid>
</UserControl>
Code behind:
using EasyInvoice.UI.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EasyInvoice.UI
{
/// <summary>
/// Interaction logic for CityPicker.xaml
/// </summary>
public partial class CityPicker : UserControl
{
public CityPicker()
{
InitializeComponent();
((CityListViewModel)this.DataContext).PropertyChanged += CityPicker_PropertyChanged;
}
private void CityPicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedCity")
SetCurrentValue(SelectedCityProperty, ((CityListViewModel)this.DataContext).SelectedCity);
}
public static readonly DependencyProperty SelectedCityProperty =
DependencyProperty.Register("SelectedCity", typeof(CityViewModel), typeof(CityPicker),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public CityViewModel SelectedCity
{
get
{
return (CityViewModel)GetValue(SelectedCityProperty);
}
set
{
SetCurrentValue(SelectedCityProperty, value);
}
}
}
}
This is where I use this control:
<UserControl x:Class="EasyInvoice.UI.NewCustomerView"
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"
mc:Ignorable="d"
Height="135" Width="450"
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
xmlns:einvoice="clr-namespace:EasyInvoice.UI">
<UserControl.Resources>
<Style TargetType="xctk:WatermarkTextBox">
<Setter Property="Margin" Value="3"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<xctk:WatermarkTextBox Grid.ColumnSpan="2" Watermark="Voornaam" Text="{Binding FirstName}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="2" Watermark="Famillienaam" Grid.Column="2" Text="{Binding LastName}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="2" Watermark="Straat" Grid.Row="2" Text="{Binding Address.Street}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="1" Watermark="Huisnummer" Grid.Column="2" Grid.Row="2" Text="{Binding Address.HouseNr}"/>
<xctk:WatermarkTextBox Grid.ColumnSpan="1" Watermark="Busnummer" Grid.Column="3" Grid.Row="2" Text="{Binding Address.BusNr}"/>
<einvoice:CityPicker Grid.Row="3" Grid.ColumnSpan="4" SelectedCity="{Binding Address.City, Mode=TwoWay}"/>
<Button Grid.Row="5" Content="Opslaan en sluiten" Grid.ColumnSpan="4" Style="{StaticResource PopupButton}"/>
</Grid>
</UserControl>
And this is the ViewModel for "Address":
using EasyInvoice.Model;
using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EasyInvoice.UI.ViewModel
{
public class AddressViewModel : ViewModelBase
{
private string _street;
private string _houseNr;
private string _busNr;
private CityViewModel _city;
public AddressViewModel(Address address)
{
LoadAddress(address);
}
public AddressViewModel() : this(new Address()) { }
private Address Address { get; set; }
public string Street
{
get
{
return _street;
}
set
{
if (_street == value)
return;
_street = value;
RaisePropertyChanged("Street");
}
}
public string HouseNr
{
get
{
return _houseNr;
}
set
{
if (_houseNr == value)
return;
_houseNr = value;
RaisePropertyChanged("HouseNr");
}
}
public string BusNr
{
get
{
return _busNr;
}
set
{
if (_busNr == value)
return;
_busNr = value;
RaisePropertyChanged("BusNr");
}
}
public string BusNrParen
{
get
{
return string.Concat("(", BusNr, ")");
}
}
public bool HasBusNr
{
get
{
return !string.IsNullOrWhiteSpace(_busNr);
}
}
public CityViewModel City
{
get
{
return _city;
}
set
{
if (_city == value)
return;
_city = value;
RaisePropertyChanged("City");
}
}
public void LoadAddress(Address address)
{
this.Address = address;
if(address == null)
{
_street = "";
_houseNr = "";
_busNr = "";
_city = new CityViewModel(null);
}
else
{
_street = address.StreetName;
_houseNr = address.HouseNr;
_busNr = address.BusNr;
_city = new CityViewModel(address.City);
}
}
}
}
When I'm debugging, I can see that this line is reached when I change the property in my UI:
SetCurrentValue(SelectedCityProperty, ((CityListViewModel)this.DataContext).SelectedCity);
But somehow, this never gets set:
public CityViewModel City
{
get
{
return _city;
}
set
{
if (_city == value)
return;
_city = value;
RaisePropertyChanged("City");
}
}
Also, I'm sure the viewmodel is wired up correctly, because I set a breakpoint at "HouseNr" and this works correctly.
Just in case there is not enough provided, the project can be found here: https://github.com/SanderDeclerck/EasyInvoice
From your code
public CityViewModel SelectedCity
{
get
{
return (CityViewModel)GetValue(SelectedCityProperty);
}
set
{
SetCurrentValue(SelectedCityProperty, value);
}
}
Change this
SetCurrentValue(SelectedCityProperty, value);
to this
SetValue(SelectedCityProperty, value);
Issue is in your binding. You have set DataContext of UserControl to CityListViewModel so binding is failing since binding engine is searching for property Address.City in CityListViewModel instead of AddressViewModel.
You have to explicitly resolve that binding using RelativeSource or ElementName.
SelectedCity="{Binding DataContext.Address.City,RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=UserControl}, Mode=TwoWay}"
OR
Give x:Name to UserControl say NewCustomer and bind using ElementName.
SelectedCity="{Binding DataContext.Address.City, ElementName=NewCustomer}"
Also you can avoid setting Mode to TwoWay since you have already specified that at time of registering of DP.

Categories

Resources