binding not working windows phone 7 - c#

hi guys am trying to bind some data.
i have a list of people . on tap of each of these i take the user to details page.
on tap of each item i get the data from the web and parse it.
public ObservableCollection<ItemViewModel> PeopleDetails { get; set; }
the above line i have declared in my MainViewModel
ItemViewModel.cs
public class ItemViewModel : INotifyPropertyChanged
{
private string _person_name;
public string _Person_name
{
get { return _person_name; }
set
{
if (value != _person_name)
{
_person_name= value;
NotifyPropertyChanged("_Person_name");
}
}
}
private string _person_info;
public string _Person_info
{
get { return _person_info; }
set
{
if (value != _person_info)
{
_person_info= value;
NotifyPropertyChanged("_Person_info");
}
}
}
private string _person_image_link;
public string _Person_image_link
{
get { return _person_image_link; }
set
{
if (value != _person_image_link)
{
_person_image_link= value;
NotifyPropertyChanged("_Person_image_link");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
on tap of each item am executing the following code
private void getPeopleDetails(object sender, SelectionChangedEventArgs e)
{
// Navigate to the new page
if (e.AddedItems != null && e.AddedItems.Count == 1)
{
People selectedItem = (People)e.AddedItems[0];
NavigationService.Navigate(new Uri("/PeopleDetailsView.xaml?id="+selectedItem.id, UriKind.Relative));
}
}
then in PeopleDetailsView.xaml.cs my code is as follows
public PeopleDetailsView()
{
DataContext = App.Model;
InitializeComponent();
Loaded+=new RoutedEventHandler(PeopleDetailsView_Loaded);
}
private void PeopleDetailsView_Loaded(Object sender ,RoutedEventArgs e){
string id = "";
if (NavigationContext.QueryString.TryGetValue("id",out id))
{
string url = "*****&id=" + id;";
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompletedC);
client.DownloadStringAsync(new Uri(url));
}
}
private void client_DownloadStringCompletedC(object sender, DownloadStringCompletedEventArgs e)
{
try
{
JToken a = JObject.Parse(e.Result);
App.Model.PeopleDetails.Add(
new ItemViewModel()
{
_Person_info = a.SelectToken("info").ToString(),
_Person_image_link = a.SelectToken("image_link").ToString(),
_Person_name = a.SelectToken("name").ToString(),
}
);
}
catch (Exception execp)
{
MessageBox.Show(execp.Message.ToString());
}
}
and finally am binding the data in my PeopleDetailsView.xaml as follows
<Grid x:Name="ContentPanel" DataContext="{Binding PeopleDetails}" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="269*" />
<RowDefinition Height="338*" />
</Grid.RowDefinitions>
<Image Height="250" HorizontalAlignment="Left" Margin="12,6,0,0" Name="image1" Stretch="Fill" Source="{Binding _Person_image_link}" VerticalAlignment="Top" Width="246" />
<ScrollViewer Grid.Row="1" Height="274" HorizontalAlignment="Left" Margin="12,42,0,0" Name="scrollViewer1" VerticalAlignment="Top" Width="420">
<TextBlock Height="264" Name="textBlock1" Text="{Binding _Person_info}" />
</ScrollViewer>
</Grid>
</Grid>
but in the PeopleDetailsView i cant see any data being displayed. Please help me

You're ViewModel has an ObservableCollection of items and you're binding directly to a property of one of the children. Instead you should use a ListBox and template your binding:
<ListBox x:Name="ContentPanel" ItemsSource="{Binding PeopleDetails}" Grid.Row="1" Margin="12,0,12,0">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Height="250" HorizontalAlignment="Left" Margin="12,6,0,0" Name="image1" Stretch="Fill" Source="{Binding _Person_image_link}" VerticalAlignment="Top" Width="246" />
<ScrollViewer Grid.Row="1" Height="274" HorizontalAlignment="Left" Margin="12,42,0,0" Name="scrollViewer1" VerticalAlignment="Top" Width="420">
<TextBlock Height="264" Name="textBlock1" Text="{Binding _Person_info}" />
</ScrollViewer>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Related

C# WPF XAML Toolkit, switch views with button click

I am using Material Design in XAML Toolkit. I have the main window with drawer, which contains the list of user controls (app tabs). When I click on them - application tab switches between this controls. I want to add a button to the window, and when I click on it I want to switch between tabs too. You can see important parts of my code here:
<materialDesign:DialogHost Identifier="RootDialog" SnackbarMessageQueue="{Binding ElementName=MainSnackbar, Path=MessageQueue}">
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding ElementName=MenuToggleButton, Path=IsChecked}">
<materialDesign:DrawerHost.LeftDrawerContent>
<DockPanel MinWidth="212">
<ToggleButton Style="{StaticResource MaterialDesignHamburgerToggleButton}"
DockPanel.Dock="Top"
HorizontalAlignment="Right" Margin="16"
IsChecked="{Binding ElementName=MenuToggleButton, Path=IsChecked, Mode=TwoWay}" />
<ListBox x:Name="DemoItemsListBox" Margin="0 16 0 16" SelectedIndex="0"
ItemsSource="{Binding DemoItems}"
PreviewMouseLeftButtonUp="UIElement_OnPreviewMouseLeftButtonUp">
<ListBox.ItemTemplate>
<DataTemplate DataType="helpers:DemoItem">
<TextBlock Text="{Binding Name}" Margin="32 0 32 0" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</materialDesign:DrawerHost.LeftDrawerContent>
<DockPanel>
<materialDesign:ColorZone Padding="16" materialDesign:ShadowAssist.ShadowDepth="Depth2"
Mode="PrimaryDark" DockPanel.Dock="Top">
<DockPanel>
<ToggleButton Style="{StaticResource MaterialDesignHamburgerToggleButton}" IsChecked="False"
x:Name="MenuToggleButton"/>
<materialDesign:PopupBox x:Name="popupBox">
<TextBlock>Check me please</TextBlock>
</materialDesign:PopupBox>
<CheckBox x:Name="LizenzeCheckBox" DockPanel.Dock="Right" Style="{StaticResource MaterialDesignCheckBox}" Tag="False">
<CheckBox.IsChecked>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}">
<Binding.ValidationRules>
<helpers:IsCheckedValidationRule />
</Binding.ValidationRules>
</Binding>
</CheckBox.IsChecked>CheckBox text</CheckBox>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="22">My App</TextBlock>
</DockPanel>
</materialDesign:ColorZone>
<Button x:Name="TheBUTTON" Click="Button_Click">Ckicc</Button>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="1"
HorizontalScrollBarVisibility="{Binding ElementName=DemoItemsListBox, Path=SelectedItem.HorizontalScrollBarVisibilityRequirement}"
VerticalScrollBarVisibility="{Binding ElementName=DemoItemsListBox, Path=SelectedItem.VerticalScrollBarVisibilityRequirement}"
Padding="{Binding ElementName=DemoItemsListBox, Path=SelectedItem.MarginRequirement}">
<ContentControl Content="{Binding ElementName=DemoItemsListBox, Path=SelectedItem.Content}" />
</ScrollViewer></Grid>
This is my main window xaml code, as you can see, I bind ListBox Values to DemoItem[] array from viewModel. "TheButton" onclick event is the event which I want to use for tab switching.
My main window view model is:
public class MainWindowViewModel
{
public DemoItem[] DemoItems { get; }
public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue)
{
if (snackbarMessageQueue == null) throw new ArgumentNullException(nameof(snackbarMessageQueue));
DemoItems = new[]
{
new DemoItem("Tab1", new Tab1()),
new DemoItem("Tab2", new Tab2()),
new DemoItem("Tab3", new Tab3()),
};
}
}
The MainWindow.cs is:
public partial class MainWindow : Window
{
public static Snackbar Snackbar;
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
}).ContinueWith(t =>
{
MainSnackbar.MessageQueue.Enqueue("Welcome to my app");
}, TaskScheduler.FromCurrentSynchronizationContext());
DataContext = new MainWindowViewModel(MainSnackbar.MessageQueue);
}
private void UIElement_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//until we had a StaysOpen glag to Drawer, this will help with scroll bars
var dependencyObject = Mouse.Captured as DependencyObject;
while (dependencyObject != null)
{
if (dependencyObject is ScrollBar) return;
dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
}
MenuToggleButton.IsChecked = false;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//what to do here?
}
}
The DemoItem Class is:
public class DemoItem : INotifyPropertyChanged
{
private string _name;
private object _content;
private ScrollBarVisibility _horizontalScrollBarVisibilityRequirement;
private ScrollBarVisibility _verticalScrollBarVisibilityRequirement;
private Thickness _marginRequirement = new Thickness(16);
public DemoItem(string name, object content)
{
_name = name;
Content = content;
}
public string Name
{
get { return _name; }
set { this.MutateVerbose(ref _name, value, RaisePropertyChanged()); }
}
public object Content
{
get { return _content; }
set { this.MutateVerbose(ref _content, value, RaisePropertyChanged()); }
}
public ScrollBarVisibility HorizontalScrollBarVisibilityRequirement
{
get { return _horizontalScrollBarVisibilityRequirement; }
set { this.MutateVerbose(ref _horizontalScrollBarVisibilityRequirement, value, RaisePropertyChanged()); }
}
public ScrollBarVisibility VerticalScrollBarVisibilityRequirement
{
get { return _verticalScrollBarVisibilityRequirement; }
set { this.MutateVerbose(ref _verticalScrollBarVisibilityRequirement, value, RaisePropertyChanged()); }
}
public Thickness MarginRequirement
{
get { return _marginRequirement; }
set { this.MutateVerbose(ref _marginRequirement, value, RaisePropertyChanged()); }
}
public event PropertyChangedEventHandler PropertyChanged;
private Action<PropertyChangedEventArgs> RaisePropertyChanged()
{
return args => PropertyChanged?.Invoke(this, args);
}
}
My MutateVerbose function looks like:
public static void MutateVerbose<TField>(this INotifyPropertyChanged instance, ref TField field, TField newValue, Action<PropertyChangedEventArgs> raise, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<TField>.Default.Equals(field, newValue)) return;
field = newValue;
raise?.Invoke(new PropertyChangedEventArgs(propertyName));
}
I don't know how to switch tabs with button click in this situation. Help me, please!

ComboBox Selected Item not updating

Problem
I am trying to bind a ComboBox's SelectedItem to a custom class but this does not update when the property is changed.INotifyPropertyChanged is implemented.
The DataContext
The DataContext is a custom class which contains many properties, but an extract of this is below. You can see it implements INotifyPropertyChanged and this called when the two properties are changed.
public class BctsChange : INotifyPropertyChanged
{
#region declarations
private byContact _Engineer;
public byContact Engineer
{
get { return _Engineer; }
set
{
_Engineer = value;
NotifyPropertyChanged("Engineer");
OnEngineerChanged();
}
}
private BctsSvc.DOSets _LeadingSet;
public BctsSvc.DOSets LeadingSet
{
get { return _LeadingSet; }
set { _LeadingSet = value; NotifyPropertyChanged("LeadingSet"); }
}
#endregion
#region INotify
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public BctsChange()
{
Engineer = new byContact(Environment.UserName);
}
private void OnEngineerChanged()
{
if (Engineer != null)
{
BctsSvc.DOSets leadSet = GetLeadingSetFromDeptCode(Engineer.DeptCode);
if (leadSet == null) return;
LeadingSet = leadSet;
}
}
private static BctsSvc.DOSets GetLeadingSetFromDeptCode(string DeptCode)
{
BctsSvc.BctsServiceSoapClient svc = new BctsSvc.BctsServiceSoapClient();
BctsSvc.DOSets setX = svc.GetSetFromDeptCode(DeptCode);
return setX;
}
}
The Window XAML
I have several controls on the window, but to keep the code simple I believe the following extract will suffice.
<Window x:Class="MyNamespace.wdSubmit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:MyNamespace"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="ucReqForm"
Title="wdSubmit" >
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<GroupBox Header="Engineer Details" Name="grpOwnerDetails" >
<StackPanel Orientation="Vertical">
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="35"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Engineer.FullName, FallbackValue='Please select an engineer by clicking →', Mode=OneWay}" Margin="5,0" IsEnabled="True" FontStyle="Italic" />
<Button Content="{StaticResource icoSearch}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="1" Height="23" Name="btnSelectEngineer" Margin="0,0,5,0" HorizontalAlignment="Stretch" ToolTip="Search for an engineer responsible" Click="btnSelectEngineer_Click" />
</Grid>
<ComboBox Height="23" x:Name="ddSet2" Margin="5,0" ItemsSource="{Binding LeadingSets, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" SelectedItem="{Binding LeadingSet, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SetName}" ToolTip="{Binding HelpInfo}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<my:LabelledDropdown Height="23" x:Name="ddSet" Margin="5,0" ItemsSource="{Binding LeadingSets, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" SelectedItem="{Binding LeadingSet, Mode=TwoWay,NotifyOnTargetUpdated=True,NotifyOnSourceUpdated=True}" Label="e.g. BodyHardware">
<my:LabelledDropdown.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding SetName}" ToolTip="{Binding HelpInfo}"/>
</DataTemplate>
</my:LabelledDropdown.ItemTemplate>
</my:LabelledDropdown>
</StackPanel>
</GroupBox>
</StackPanel>
</Window>
The above extract contains:
A Label that contains a contact's name, and a button to search for a contact, bound to the FullName of the Engineer
A ComboBox that contains departments within the company, bound to an ObservableCollection<DOSets>, which contains a list of departments
Two ComboBoxes, one which is a custom one and the other which is temporary to ensure the bug is not within the control. These are Databound to LeadingSet
Window Code Behind
In the code behind I set the DataContext to CurrentChange. When the user wants to select a different Engineer then this will update the selected department for the engineer in CurrentChange.
When the user changes the engineer, the data binding for the engineer is updated, but the selected department (Leading Set) isn't.
//Usings here
namespace MyNamespace
{
public partial class wdSubmit : Window, INotifyPropertyChanged
{
private BctsSvc.BctsServiceSoapClient svc;
private BctsChange _CurrentChange;
public BctsChange CurrentChange
{
get { return _CurrentChange; }
set { _CurrentChange = value; OnPropertyChanged("CurrentChange"); }
}
private List<BctsSvc.DOSets> _LeadingSets;
public List<BctsSvc.DOSets> LeadingSets
{
get
{
return _LeadingSets;
}
}
public wdSubmit()
{
InitializeComponent();
svc = new BctsSvc.BctsServiceSoapClient();
_LeadingSets = svc.GetLeadSets().ToList();
OnPropertyChanged("LeadingSets");
this._CurrentChange = new BctsChange();
this.DataContext = CurrentChange;
CurrentChange.PropertyChanged += new PropertyChangedEventHandler(CurrentChange_PropertyChanged);
}
void CurrentChange_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged("CurrentChange");
OnPropertyChanged(e.PropertyName);
}
private void btnSelectEngineer_Click(object sender, RoutedEventArgs e)
{
byContact newContact = new frmSearchEngineer().ShowSearch();
if (newContact != null)
{
CurrentChange.Engineer = newContact;
PropertyChanged(CurrentChange, new PropertyChangedEventArgs("LeadingSet"));
PropertyChanged(CurrentChange.LeadingSet, new PropertyChangedEventArgs("LeadingSet"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(CurrentChange, new PropertyChangedEventArgs(propertyName));
}
}
}
I've realised the problem may be due to the LeadingSet, returned when the engineer is changed, being a different instance to that in the ObservableCollection.

WPF ListBox Not updating

I searched in this forum but I was unable to find a solution for my specific scenario.
I`m trying to understand WPF and MVVM and I build a simple WPF for this.
My Data Model is (I Implemented INotifyPropertyChanged here and the constructor initializes all properties):
namespace MyApp.ui.Models
{
public class Server : INotifyPropertyChanged
{
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged(Name); }
}
private string ipAddress;
public string IPAddress
{
get { return ipAddress; }
set { ipAddress = value; OnPropertyChanged(IPAddress); }
}
public Server(int ServerID, string ServerName, string ServerIpAddress)
{
ID = ServerID;
Name = ServerName;
IPAddress = ServerIpAddress;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
{
handler(this, new PropertyChangedEventArgs( propertyName ) );
}
}
}
}
My ViewModel (used by WPF Code Behind):
namespace MyApp.ui.ViewModels
{
public class ServersViewModel
{
private ObservableCollection<Server> server;
public ObservableCollection<Server> Servers
{
get { return server; }
set { server = value; }
}
public ServersViewModel()
{
Servers = new ObservableCollection<Server>
{
new Server(001, "Server001", #"192.168.254.3"),
new Server(002, "Server002", #"100.92.0.200"),
new Server(003, "Server003", #"64.32.0.3"),
new Server(004, "Server004", #"172.10.0.4"),
new Server(005, "Server005", #"165.23.0.233"),
new Server(006, "Server006", #"81.22.22.6"),
new Server(007, "Server007", #"10.10.0.7")
};
}
public void ChangeServerNames()
{
//Before Change
foreach (var item in Servers)
{
MessageBox.Show(item.Name);
}
int count = 1000;
foreach (var item in Servers)
{
item.Name = "Server" + count.ToString();
count += 1000;
}
//After Change
foreach (var item in Servers)
{
MessageBox.Show(item.Name);
}
}
}
}
My WPF Main View (Main Menu) loads a Custom user control (ExplorerView) with the following XAML code (Contains a listbox and each listbox item contains 1 checkbox + image + textblock)
<UserControl x:Class="MyApp.ui.Views.ExplorerView"
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"
xmlns:local="clr-namespace:MyApp.ui.Views"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="200">
<Grid>
<ListBox ItemsSource="{Binding Servers}" Margin="2">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox VerticalContentAlignment="Center" Margin="4">
<StackPanel Orientation="Horizontal">
<Image Source="/resources/server64.png" Height="30" Margin="4"></Image>
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center" Margin="4"></TextBlock>
</StackPanel>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
Finally the MainView Code Behind loads the ServersViewModel so the ExplorerView Control can Bind the data.
namespace MyApp.ui
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ServersViewModel context { get; set; }
public MainWindow()
{
InitializeComponent();
context = new ServersViewModel();
DataContext = context;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
context.ChangeServerNames();
}
}
}
That said, I have 2 Questions:
1) As you can see, in the MainView I implemented a Button click event that calls into ServersViewModel.ChangeServerNames() Method. The problem is that my TextBlock in ExplorerView Control does not show the updated data.
I ChangeServerNames() I also use a MessageBox to show the Values Before and After the change, and I see that the values are changing, not sure why the ListBox/TextBlock is not updating...!!! (I already tested many other possible solutions, but I can`t get it working...)
2) I read that the CodeBehind in MainView (and all other views) should only contain the InitializeComponent(); and "DataContext = context;" at Maximum...
If that is true, where the Events for button clicks and others should be placed?
Finally the code for the MainWindow XAML:
<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"
xmlns:local="clr-namespace:MyApp.ui"
xmlns:Views="clr-namespace:MyApp.ui.Views"
x:Class="MyApp.ui.MainWindow"
mc:Ignorable="d"
Title="Server" MinHeight="720" MinWidth="1024"
Height ="720" Width="1024">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="41*"/>
<RowDefinition Height="608*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<GridSplitter Grid.Column="1" Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Background="Gray"
ShowsPreview="True"
Width="4" Margin="0,2,0,4"
/>
<Views:MenuView Grid.ColumnSpan="3"/>
<Views:FooterView Grid.Row="2" Grid.ColumnSpan="3" />
<Views:ExplorerView Grid.Column="0" Grid.Row="1" />
<!--Temp Tests-->
<StackPanel Margin="12" Grid.Column="3" Grid.Row="1" Width="Auto" Height="Auto" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
<Button Margin="4" Width="120" Height="30" Content="Change Data Test..." Click="Button_Click" />
</StackPanel>
</Grid>
</Window>
Thank you for your time...
Ok, I found the problem...
Instead of
set { name = value; OnPropertyChanged(Name); }
set { ipAddress = value; OnPropertyChanged(IPAddress); }
I was missing the Quotesfor the String argument on method call
The correct form is
set { name = value; OnPropertyChanged("Name"); }
set { ipAddress = value; OnPropertyChanged("IPAddress"); }
Weird that the compiler didn`t throw any error.... The Method
private void OnPropertyChanged(string propertyName)
Is "Asking" for a string as input arg.
AnyWay the best to avoid these errors (that I found) is to write the event like this (The caller supplies it`s own Public Name):
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Now I can do
set { name = value; OnPropertyChanged(); }
set { ipAddress = value; OnPropertyChanged(); }
Thank you.

DataTemplate is not generating ListItemBox

I want to generate ListItemBox using DataTemplate but items are not generating. Please guide me where is the mistake. I have following code in MainWindow.xaml.
<Window x:Class="Offline_Website_Downloader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bd="clr-namespace:Offline_Website_Downloader"
Title="Offline Website Downloader" Background="#f5f6f7" Height="500" Width="800"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<bd:BindingController x:Key="BindingControllerKey" />
<DataTemplate x:Key="DownloadedWebsitesListBox">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" Width="Auto">
<TextBlock FontWeight="Bold" FontSize="18" Width="480">
<Hyperlink NavigateUri="http://google.com">
<Label Content="{Binding Path=WebsiteTitle}" />
</Hyperlink>
</TextBlock>
<TextBlock Width="132" TextAlignment="right">
<TextBlock Text="Remaining Time: "/>
<TextBlock Name="TimeRemaining" Text="js"/>
</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<ProgressBar Name="progress1" Maximum="100" Minimum="0" Value="30" Background="#FFF" Width="612" Height="10" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" Width="450">Status: <TextBlock Text="{Binding Path=Status}"/></TextBlock>
<TextBlock Width="162" TextAlignment="right">
<TextBlock Text="Downloading Speed: "/>
<TextBlock Name="DownloadingSpeed" Text="{Binding Path=DownloadingSpeed}"/>
</TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox Width="Auto"
Name="WebsiteList"
Grid.Column="1"
Grid.Row="2"
Grid.RowSpan="2"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource DownloadedWebsitesListBox}"
Margin="0,0,0,0">
</ListBox>
</Grid>
</window>
and MainWindow.xaml.cs
BindingController bc = new BindingController();
public MainWindow()
{
InitializeComponent();
bc.DownloadingSpeed = "40kb/s";
bc.WebsiteTitle = "WebsiteTitle";
bc.Status = "Downloading";
DataContext = bc;
}
and BindingController.cs
public class BindingController
{
public BindingController()
{
}
private string _WebsiteTitle;
public string WebsiteTitle
{
set { _WebsiteTitle = value; }
get { return _WebsiteTitle; }
}
private string _Status;
public string Status
{
set { _Status = value ; }
get { return _Status ; }
}
private string _DownloadStartDate;
public string DownloadStartDate
{
set { _DownloadStartDate = value; }
get { return _DownloadStartDate ; }
}
private string _DownloadingSpeed = "0 kb/s";
public string DownloadingSpeed
{
set { _DownloadingSpeed = value; }
get { return _DownloadingSpeed; }
}
}
Your problem is that you're binding a ListBox to an object that contains several properties, but really only represents a single object/state. The ListBox expects to display a list of items (i.e. IList, IBindingList, IEnumerable, ObservableCollection).
Assuming you want to display more than one download at a time, which I'm assuming given that you're using a ListBox, I would refactor the download properties into a separate class. You will also need to implement INotifyPropertyChanged on your properties so that when the values are changed, they will be shown in the UI.
public class Download : INotifyPropertyChanged
{
private string _WebsiteTitle;
public string WebsiteTitle
{
get { return _WebsiteTitle; }
set
{
if (_WebsiteTitle == value)
return;
_WebsiteTitle = value;
this.OnPropertyChanged("WebsiteTitle");
}
}
private string _Status;
public string Status
{
get { return _Status; }
set
{
if (_Status == value)
return;
_Status = value;
this.OnPropertyChanged("Status");
}
}
private string _DownloadStartDate;
public string DownloadStartDate
{
get { return _DownloadStartDate; }
set
{
if (_DownloadStartDate == value)
return;
_DownloadStartDate = value;
this.OnPropertyChanged("DownloadStartDate");
}
}
private string _DownloadingSpeed = "0 kb/s";
public string DownloadingSpeed
{
get { return _DownloadingSpeed; }
set
{
if (_DownloadingSpeed == value)
return;
_DownloadingSpeed = value;
this.OnPropertyChanged("DownloadingSpeed");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if(this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The new BindingController:
public class BindingController
{
public BindingController()
{
this.Downloads = new ObservableCollection<Download>();
}
public ObservableCollection<Download> Downloads { get; private set; }
}
Setting up the bindings in XAML:
<ListBox Width="Auto"
Name="WebsiteList"
Grid.Column="1"
Grid.Row="2"
Grid.RowSpan="2"
ItemsSource="{Binding Downloads}"
ItemTemplate="{StaticResource DownloadedWebsitesListBox}"
Margin="0,0,0,0">
</ListBox>
Initializing the collection in MainWindow
Download download = new Download();
download.DownloadingSpeed = "40kb/s";
download.WebsiteTitle = "WebsiteTitle";
download.Status = "Downloading";
bc.Downloads.Add(download);
this.DataContext = bc;

populating data to second combo box on first combo box selection change in wpf application

I am developing a wpf application. here i have to populate 2nd combo box based on the first combo box selection.
my xaml as follows:
<Grid Height="194" Width="486">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="82*" />
<ColumnDefinition Width="404*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="72*" />
<RowDefinition Height="122*" />
</Grid.RowDefinitions>
<Label Content="Category" Height="28" HorizontalAlignment="Left" Margin="13,36,0,0" Name="lblCategory" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="18,32,0,0" Name="txtScenario" VerticalAlignment="Top" Width="343" Text="{Binding Scenario_Desc}" Grid.Column="1" Grid.Row="1" />
<Button Content="Save" Command="{Binding SaveData}" Height="23" HorizontalAlignment="Left" Margin="194,71,0,0" Name="btnSave" VerticalAlignment="Top" Width="75" Grid.Row="1" Grid.Column="1" />
<Button Content="Reset" Command="{Binding ClearData}" Height="23" HorizontalAlignment="Left" Margin="286,71,0,0" Name="btnReset" VerticalAlignment="Top" Width="75" Grid.Row="1" Grid.Column="1" />
<Label Content="Sub Category" Height="28" HorizontalAlignment="Left" Margin="13,70,0,0" Name="lblSubCategory" VerticalAlignment="Top" Grid.RowSpan="2" Grid.ColumnSpan="2" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="18,36,0,0" Name="cboCategory" VerticalAlignment="Top" Width="343"
ItemsSource="{Binding Path=Category}"
DisplayMemberPath="Category_Desc"
SelectedValuePath="Category_Id"
SelectedValue="{Binding Path=Category_Id, Mode=TwoWay}"
SelectedIndex="0"
Text="{Binding Category_Desc}" Grid.Column="1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding CategorySelected}"
CommandParameter="{Binding SelectedValue, ElementName=cboCategory}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<Label Content="Scenario" Grid.ColumnSpan="2" Height="28" HorizontalAlignment="Left" Margin="12,32,0,0" Name="lblScenario" VerticalAlignment="Top" Grid.Row="1" />
<ComboBox Height="23" HorizontalAlignment="Left" VerticalAlignment="Top" Width="343" Grid.Column="1" Grid.RowSpan="2" ItemsSource="{Binding Path=SubCategory}" Margin="18,70,0,0" Name="cboSubCategory"
DisplayMemberPath="Sub_Category_Desc"
SelectedValue="{Binding Path=Sub_Category_Id}"
SelectedValuePath="Sub_Category_Id"
Text="{Binding Sub_Category_Desc}" />
</Grid>
When I save, I want to clear all data and show the form to allow fresh selection.
When I save, throws an error.
System.NullReferenceException was unhandled
Message=Object reference not set to an instance of an object.
StackTrace: RelayCommand`1.CanExecute(Object parameter) .....
at System.Windows.Interactivity.InvokeCommandAction.Invoke(Object parameter)
my view model code is as follows.
namespace MYOWN
{
public class ScenarioViewModel:BaseViewModel
{
private ScenarioModel scenarioModel;
public event EventHandler<ModelViewEventArgs> Reset = delegate { };
ObservableCollection<CategoryViewModel> category = new ObservableCollection<CategoryViewModel>();
ObservableCollection<SubCategoryViewModel> subCategory = new ObservableCollection<SubCategoryViewModel>();
public ScenarioViewModel()
{
scenarioModel = new ScenarioModel();
scenarioModel.isNew = true;
PopulateCategory();
}
public ScenarioViewModel( ScenarioModel scenario)
{
this.scenarioModel = scenario;
PopulateCategory();
}
private void PopulateCategory()
{
List<BaseModel> categoryModelList = DataManger.GetData((BaseModel)new CategoryModel());
foreach (CategoryModel cat in categoryModelList)
{
category.Add(new CategoryViewModel(cat));
}
}
private void PopulateSubCategory(int category_id)
{
//clear the exsisting list
subCategory.Clear();
SubCategoryModel model = new SubCategoryModel();
model.category_id = category_id;
//get the sub Category data for given category
List<BaseModel> subCategoryModelList = DataManger.GetData(model);
//populate the collection
foreach (SubCategoryModel cat in subCategoryModelList)
{
subCategory.Add(new SubCategoryViewModel(cat));
}
}
public ObservableCollection<SubCategoryViewModel> SubCategory
{
get { return subCategory; }
set { subCategory = value; }
}
public ObservableCollection<CategoryViewModel> Category
{
get { return category; }
set { category = value; }
}
public ScenarioModel ScenarioModel
{
get { return scenarioModel; }
set { scenarioModel = value; }
}
public Int32 Scenario_Id
{
get
{
return scenarioModel.scenario_id;
}
set
{
scenarioModel.scenario_id = value;
RaisePropertyChanged("Scenario_Id");
}
}
public string Scenario_Desc
{
get
{
return scenarioModel.scenario_desc;
}
set
{
scenarioModel.scenario_desc = value;
RaisePropertyChanged("Scenario_Desc");
}
}
public Int32 Sub_Category_Id
{
get
{
return scenarioModel.sub_category_id;
}
set
{
scenarioModel.sub_category_id = value;
RaisePropertyChanged("Sub_Category_Id");
}
}
string sub_category_desc;
public string Sub_Category_Desc
{
get
{
return sub_category_desc;
}
set
{
sub_category_desc = value;
RaisePropertyChanged("Sub_Category_Desc");
}
}
int category_id;
public int Category_Id
{
get
{
return category_id;
}
set
{
category_id = value;
RaisePropertyChanged("Category_Id");
}
}
string category_desc;
public string Category_Desc
{
get
{
return category_desc;
}
set
{
category_desc = value;
RaisePropertyChanged("Category_Desc");
}
}
#region Commands
protected void SelectSubCategoryDataExecute(int param=0)
{
PopulateSubCategory(param);
}
protected bool CanSelectSubCategoryDataExecute(int param=0)
{
return true;
}
public ICommand CategorySelected
{
get
{
return new RelayCommand<int>(SelectSubCategoryDataExecute, CanSelectSubCategoryDataExecute);
}
}
protected override void SaveMasterDataExecute()
{
DataManger.Save((BaseModel)scenarioModel);
//Clear once Save the data
OnReset();
}
protected override bool CanSaveMasterDataExecute()
{
return true;
}
protected void OnReset()
{
ScenarioViewModel viewModel = new ScenarioViewModel();
if (viewModel != null)
{
Reset(this, new ModelViewEventArgs(viewModel));
}
}
protected override void ResetDataExecute()
{
OnReset();
}
protected override bool CanResetDataExecute()
{
return true;
}
#endregion
}
}
I want to get the parameter value from combo box one and use that to populate to the second.
First time loading is file, when saving, the CategorySelected commnd expects a parameter, but it is assigned null. How to handle the null value in the RelayCommand....
It sound like you should use Master Details Pattern.
here are examples showing how correctly implement the pattern in wpf.
WPF Master Details MVVM Application
MSDN Article
ps:
dont forget to set IsSynchronizedWithCurrentItem="true"

Categories