C# WPF XAML Toolkit, switch views with button click - c#

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!

Related

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.

menuflyout choosed item passing to command mvvm

I'm trying to bind menuflyoutitem of choosen item in listview to Delete Command. Flyoutmenu shows when I'm holding element on list, so I can't bind it to SelectedItem property in viewmodel.
SelectedItem property works fine, but i have to tap element first and then hold item for showing menu and then delete. How can i pass sender from Holding to my property in viewmodel?
View:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="My List App"
HorizontalAlignment="Center"
Style="{ThemeResource HeaderTextBlockStyle}" />
<ListView x:Name="myListView"
Grid.Row="1"
ItemsSource="{Binding AllMyLists}"
SelectedItem="{Binding SelectedList, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Holding">
<controls:OpenMenuFlyoutAction />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Delete"
Command="{Binding ElementName=myListView, Path=DataContext.DeleteEntryListCommand}" />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<TextBlock Text="{Binding Name}"
Style="{ThemeResource ListViewItemTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
OpenMenuFlyoutAction for used for showing flyoutMenu:
public class OpenMenuFlyoutAction : DependencyObject, IAction
{
public object Execute(object sender, object parameter)
{
FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender);
return sender;
}
}
And My ViewModel:
public class AllListsPageViewModel : Microsoft.Practices.Prism.Mvvm.ViewModel, Interfaces.IAllListsPageViewModel
{
#region Fields
private ObservableCollection<EntryList> _allMyLists;
private EntryList _selectedList;
private DelegateCommand _addEntryListCommand;
private DelegateCommand _deleteEntryListCommand;
private readonly INavigationService _navigationService;
#endregion //Fields
#region Construction
public AllListsPageViewModel(INavigationService navigationService) { ... }
#endregion //Construction
#region Properties
public ObservableCollection<EntryList> AllMyLists
{
get { return _allMyLists; }
set { SetProperty(ref _allMyLists, value); }
}
public EntryList SelectedList
{
get { return _selectedList; }
set { SetProperty(ref _selectedList, value); }
}
#endregion //Properties
#region Methods
private void loadData() { }
private bool _canAddEntryList() { return true; }
private void _addEntryList() { ... }
private bool _canDeleteEntryList() { ... }
private void _deleteEntryList()
{
//How to get sender from holding event here?
_allMyLists.Remove(_selectedList);
}
#endregion //Methods
#region Commands
public ICommand AddEntryListCommand { ... }
public ICommand DeleteEntryListCommand
{
get
{
if (_deleteEntryListCommand == null)
{
_deleteEntryListCommand = new DelegateCommand(_deleteEntryList, _canDeleteEntryList);
}
return _deleteEntryListCommand;
}
}
#endregion //Commands
}
Thanks in advance.
I had the same problem today and I have resolved as follows:
namespace your.namespace
{
using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
public class OpenMenuFlyoutAction : DependencyObject, IAction
{
private static object holdedObject;
public object Execute(object sender, object parameter)
{
FrameworkElement senderElement = sender as FrameworkElement;
FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);
flyoutBase.ShowAt(senderElement);
var eventArgs = parameter as HoldingRoutedEventArgs;
if (eventArgs == null)
{
return null;
}
var element = eventArgs.OriginalSource as FrameworkElement;
if (element != null)
{
HoldedObject = element.DataContext;
}
return null;
}
public static object HoldedObject
{
get { return holdedObject; }
set
{
holdedObject = value;
}
}
}
}
Then you can access the object as follows:
var foo = OpenMenuFlyoutAction.HoldedObject as Foo;
I think it's not bad solution that the HoldedObject is static as you can not do hold two items at the same time.

Change item checkbox on ListBox selection change

I have a ListBox created by ItemTemplate and Binding
<controls:PanoramaItem Header="{Binding AppResources.SettingsSubpage2, Source={StaticResource LocalizedStrings}}" HeaderTemplate="{StaticResource HeaderTemplate}">
<Grid>
<ListBox x:Name="DayOfWeekSelector" ItemTemplate="{StaticResource DayOfWeekTemplate}" ItemsSource="{Binding DayOfWeekElementList}" Foreground="{StaticResource AppForegroundColor}" LostFocus="DayOfWeekSelector_LostFocus" HorizontalAlignment="Left" Width="420" />
</Grid>
</controls:PanoramaItem>
Template code:
<phone:PhoneApplicationPage.Resources>
<!--- ... --->
<DataTemplate x:Key="DayOfWeekTemplate">
<Grid Height="65" Width="332">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsActive, Mode=TwoWay}" Tag="{Binding}" d:LayoutOverrides="Width, Height" BorderBrush="{StaticResource AppBackgroundColor}" Background="{StaticResource ScheduleBackgroundAccentsColor}" Grid.Column="0" Unchecked="CheckBox_Unchecked" />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" d:LayoutOverrides="Width"/>
<TextBlock Text="{Binding TaskCounter, Mode=OneWay, Converter={StaticResource DayOfWeekCounter}}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,0"/>
</StackPanel>
</Grid>
</DataTemplate>
<!--- ... --->
And it's working fine. I've got all my items on the list. Checkboxes are binded to appropriate elements (clicking on it is changing proper value).
But by default ListBox can be also selected. Selection high-light TextBox binded to Name but don't change CheckBox (binded to IsActive). How can I tie item selection changing to checkbox state changing (in Silverlight)?
Edit:
public partial class SettingsPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public List<DayOfWeekElement> DayOfWeekList
{
get
{
return CyberSyncPlanBase.Instance.DayOfWeekElementList;
}
set
{
CyberSyncPlanBase.Instance.DayOfWeekElementList = value;
NotifyPropertyChanged("DayOfWeekList");
}
}
public SettingsPage()
{
InitializeComponent();
DayOfWeekSelector.DataContext = CyberSyncPlanBase.Instance;
}
private void DayOfWeekSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DayOfWeekElement dowe = (DayOfWeekElement) DayOfWeekSelector.SelectedItem;
if (dowe != null)
dowe.IsActive = (dowe.IsActive) ? false : true;
}
And in singleton INotifyPropertyChanged i've implemented in the same way:
private List<DayOfWeekElement> dayOfWeekElementList;
public List<DayOfWeekElement> DayOfWeekElementList
{
get { return dayOfWeekElementList; }
set
{
dayOfWeekElementList = value;
RecalcWeekTasks();
NotifyPropertyChanged("DayOfWeekElementList");
}
}
Bottom class:
public class DayOfWeekElement
{
public string Name { get { return this.DayOfWeek.ToStringValue(); } }
public bool IsNotEmpty { get { return (TaskCounter > 0); } }
public int TaskCounter { get; set; }
public bool IsActive { get; set; }
public DayOfWeek DayOfWeek { get; set; }
}
I think you could use the SelectedItem property of the ListBox control.
A possible implementation could be this:
Subscribe to the event SelectedIndexChanged of the ListBox.
Get the selected item.
For the selected item, change its IsActive property to true.
This works if the interface INotifyPropertyChanged is implemented in your data class.
E.g.:
public class DayOfWeekElement : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool isActive = false;
public bool IsActive {
get
{
return this.isActive;
}
set
{
if (value != this.isActive)
{
this.isActive= value;
NotifyPropertyChanged("IsActive");
}
}
}
}

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;

binding not working windows phone 7

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>

Categories