I'm working on a WPF page with the following:
<ItemsControl ItemsSource="{Binding Peopl.PhoneNums}" x:Name="PhoneList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0" x:Name="PhoneEntry">
<TextBlock Text="123-456-78901"/>
<ComboBox ...>
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
There can be multiple stackpanels, each with a unique phone number; in code behind, each phone number has a flag indicating if it should be enabled; I want to be able to enable each entry in the stack panel based on that flag but I'm stuck accessing it....
I have:
foreach (Phone phone in PhoneList.ItemsSource)
{
if (phone.ShouldBeDisabled)
{
int index = PhoneList.Items.IndexOf(phone);
PhoneList.IsEnabled = false;
//this disables the entire control;
// I can't access "PhoneEntry" here... hmm
}
}
Is there a way to disable only one entry at a time? How can I access PhoneEntry? Should I try to disable the each stackpanel entry based on the bound value?
You may invert your view model property and call it ShouldBeEnabled. Now you can bind the StackPanel's IsEnabled property.
<StackPanel ... IsEnabled="{Binding ShouldBeEnabled}">
...
</StackPanel>
In case you can't change the view model, you may use a binding converter that inverts the property value:
<StackPanel ... IsEnabled="{Binding ShouldBeDisabled,
Converter={StaticResource InverseBooleanConverter}}">
...
</StackPanel>
Your Phone class would have to implement the INotifyPropertyChanged interface and fire the PropertyChanged event when the value of the ShouldBeDisabled property changes.
Related
My theory code:
ScriptContainerUserControl.xaml
<ItemsControl x:Name="ScriptItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBox x:Name="pTB" Text="{Binding PhasePriority}" />
<TextBox x:Name="nTB" Text="{Binding Name}" />
<TextBox x:Name="dTB" Text="{Binding Description}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ScriptContainerUserControl.xaml.cs
public ScriptContainerUserControl() : base()
{
InitializeComponent();
ScriptItemsControl.ItemsSource = PScriptCollection;
}
//PScriptCollecion is of type SynchronizedObservableCollection<ProcessScript>
//ProcessScript has the elements PhasePriority, Name, and Description
Would the code above work for making sure
ScriptItemsControl[i].dTB.Text = PScriptCollection[i].Description?
Or is it not possible to bind like this?
Fenster,
It should definitely work, provided you have getter setter properties implemented for all the three properties in ProcessScript class.
When you use a datatemplate - it means you are setting the datacontext of each element of your itemscontrol to an element of your collection.
so here each Itemcontrol element will look at ProcessScript object and if that object has all three properties , you should see the data.
It is not possible to do it in this way. You do not set Binding actually... To have support for observing a changes on collection you should bind the collection to ItemsSource property of ItemsControl.
Instead of line:
ScriptItemsControl.ItemsSource = PScriptCollection;
try this
ScriptItemsControl.ItemsSource = new Binding("PScriptCollection");
I have a checkbox under a listbox using the given xaml file .
My xaml file:
<ListBox x:Name="notificationSettingsListBox" Grid.Row="1" Margin="20,20,20,20" Background="#e79e38" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="#055cc3" Width="500" Height="200" Margin="30,40,30,20">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding channel_name}" Foreground="White" FontSize="31" TextAlignment="Left" TextWrapping="Wrap" Margin="0,20,10,0" />
<CheckBox x:Name="pushNotiOnCheckBox" Content="Enable Notification" Checked="pushNotiOnCheckBox_Checked" Unchecked="pushNotiOnCheckBox_Unchecked"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Suppose in my listbox i have 5 checkbox and the user just checks 2 of the checkbox. Now when the user lunches the app in next time it will show the checked state of these 2 checkbox which he previously checked.
How can i achieve that using these xaml file in windows phone ??
You can store the selected values in the settings. This settings are persisted by the system and you can read the values by starting your app:
Code sample (save):
var settings = IsolatedStorageSettings.ApplicationSettings;
// txtInput is a TextBox defined in XAML.
if (!settings.Contains("userData"))
{
settings.Add("userData", txtInput.Text);
}
else
{
settings["userData"] = txtInput.Text;
}
settings.Save();
Code sample (read):
// txtDisplay is a TextBlock defined in XAML.
if (IsolatedStorageSettings.ApplicationSettings.Contains("userData"))
{
txtDisplay.Text = IsolatedStorageSettings.ApplicationSettings["userData"] as string;
}
More Infos: See this msdn article
Then, when you start your app/show the view: You just need to check, which values are checked in the settings and then mark the CheckBox as checked. When the Checkboxes are dynamic (not static) you better make a ViewModel to achive this.
I have an ObservableCollectiong<StringWrapper> (StringWrapper per this post) named Paragraphs bound to an ItemsControl whose ItemTemplate is just a TextBox bound to StringWrapper.Text.
XAML
<ItemsControl Name="icParagraphs" Grid.Column="1" Grid.Row="7" ItemsSource="{Binding Path=Paragraphs, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<StackPanel Orientation="Vertical">
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Name="tbParagraph" TextWrapping="Wrap" AcceptsReturn="False" Text="{Binding Path=Text}" Grid.Column="0" KeyUp="tbParagraph_KeyUp" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
C#
public class StringWrapper
{
public string Text { get; set; }
public StringWrapper()
{
Text = string.Empty;
}
public StringWrapper(string text)
{
Text = text;
}
}
I'm trying to make it so when I press enter in a TextBox, I insert a StringWrapper in my ObservableCollection after the StringWrapper bound to the TextBox that's currently focused, which generates a new TextBox. So far, my code does this, though there are a couple glitches to work out.
My question is, how do I then set the focus to the newly generated TextBox? As far as I can tell, the control generation happens after the function that inserts the string returns.
I looked for something like an ItemsControl.ItemsSourceChanged event, but, at least, that name doesn't exist. I also tried attaching a handler to ObservableCollection.CollectionChanged, but that too seemed to fire before the TextBox was generated. Last, since the ItemsControl.Template is a StackPanel, I looked for a StackPanel.ControlAdded event, but couldn't find that either.
Ideas? Thanks!
You may have to handle CollectionChanged and then schedule the focus action to occur in the future using Dispatcher.BeginInvoke with a priority of Loaded. That should give the ItemsControl an opportunity to generate a container and perform layout.
I need to display hierarchical data like:
public class Element
{
public string Name { get; private set; }
public Element[] Elements { get; private set; }
}
It would be just vertical panel with rectangle (with Name) for each element. If element is clicked, its child elements are displayed below it (element is expanded). If one of them is clicked, its elements appear and so on.
I already googled this and found out that there is no HierarchicalDataTemplate and no treeview in WinRT.
So I started to do it by myself.
I created ItemsControl and DataTemplate DataTemplate1 for it. In DataTemplate1 I also create ItemsControl and set DataTemplate2 as ItemTemplate. In DataTemplate2, ItemTemplate is DataTemplate3 and so on. The last DataTemplate is without ItemsControl.
In buttons Click event I change Elements IsVisible property for any elements in DataModel (that is Element[]), so it is easy to perform any custom logic to expand/collapse elements.
<DataTemplate x:Key="DataTemplate2">
<StackPanel Visibility="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Style="{StaticResource ItemButtonStyle}"
Click="MenuElement_Click">
<TextBlock Style="{StaticResource ItemTextBlockStyle}" Text="{Binding Name}"/>
</Button>
<ItemsControl ItemsSource="{Binding Elements}" ItemTemplate="{StaticResource DataTemplate3}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DataTemplate1">
<StackPanel Visibility="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Style="{StaticResource ItemButtonStyle}"
Click="MenuElement_Click">
<TextBlock Style="{StaticResource ItemTextBlockStyle}" Text="{Binding Name}"/>
</Button>
<ItemsControl ItemsSource="{Binding Elements}" ItemTemplate="{StaticResource DataTemplate2}"/>
</StackPanel>
</DataTemplate>
It works fine, but the problem is that if I want to enable 10 levels of hierarchy, I have to copypast 10 datatemplates. And 11 level still will not be available.
I also tried to create DataTemplate in C# and manually apply DataTemplate for its ItemSource and so on, in recursive method.
But I found 2 problems.
I don't know actually how to create DataTemplate in metro (C#), because it has no VisualTree property. I can only make (var dt= new Datatemplate();) and I don't know how to change it.
If I read DataTemplate from XAML (var dateTemplateRoot = (DataTemplate)this.Resources["DataTemplate1"];)
I still can't find ItemsControl in it and change its DataTemplate.
Actually, I can use var content = dateTemplateRoot.LoadContent(); and then find ItemsControl by VisualTreeHelper, but I can't use content after that as DataTemplate (content has type DependencyObject).
So, actually I have 2 questions.
Is it a good approach to perform hierarchical dropdown list by "binding" all items and only switch Visibility property?
The second is - how to enable unlimited level of hierarchical nesting?
WinRT XAML Toolkit has a TreeView control now. Check it out: http://winrtxamltoolkit.codeplex.com/SourceControl/changeset/view/b0ee76bd6492#WinRTXamlToolkit/Controls/TreeView/TreeView.cs
Take care though - this is just a rough port from Silverlight Toolkit and might not work so well. Also if you are planning on releasing it as part of a Windows Store application - you would need to heavily restyle it unless your app is desktop-only since it is not very touch-friendly.
Windows Phone 7.1: How to add/delete items from LongListSelector control?
I am using a LongListSelector control from 'Windows Phone Toolkit'. The control is data bound to a ViewModel inherited from an ObservableCollection. When I try the following code:
MyObject mo = new MyObject("Name", "Description", "Value");
App.MyObjectsViewModel.Add(mo);
The ViewModel does seem to get updated but the LongListSelector does not update? What am I missing?
PS: I am new to Silverlight and WP7 development.
Following the XAML for the LongListSelector and the DataTemplates. The code is pretty much straight out of the Windows Phone Toolkit sample (removed some formatting related code to keep the post small)
<DataTemplate x:Key="groupHeader">
<TextBlock Text="{Binding Key}"/>
</DataTemplate>
<DataTemplate x:Key="groupItemHeader">
<Border>
<TextBlock Text="{Binding Key}"
Foreground="#FFFFFF"
FontSize="{StaticResource PhoneFontSizeLarge}"/>
</Border>
</DataTemplate>
<DataTemplate x:Key="myobjectItemTemplate">
<Grid>
<StackPanel VerticalAlignment="Top" Orientation="Vertical">
<TextBlock Text="{Binding Symbol}"/>
<TextBlock Text="{Binding Value}"/>
<TextBlock Text="{Binding Description}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
<controls:PivotItem Header="myobjects">
<toolkit:LongListSelector x:Name="myobjectsList"
Background="Transparent"
GroupHeaderTemplate="{StaticResource groupHeader}"
GroupItemTemplate="{StaticResource groupItemHeader}"
ItemTemplate="{StaticResource myobjectItemTemplate}"
GroupViewOpened="LongListSelector_GroupViewOpened"
GroupViewClosing="LongListSelector_GroupViewClosing"/>
</controls:PivotItem>
C# code behind for setting the ItemSource
var myobjectsByClassification = from myobjects in App.MyObjectsLibrary
group myobjects by myobjects.Classification into c
orderby c.Key
select new PublicGrouping<string, MyObject>(c);
this.myobjectsList.ItemsSource = myobjectsByClassification;
My guess is that the grouping code is only being called once somewhere in code behind. So the grouped collection is not updated when you add something to your ViewModel collection. The easiest way to handle this (but maybe not the most elegant) is to create your own AddItem() method for the ViewModel collection.
class MyViewModelObject
{
void AddItem( MyObject obj )
{
App.MyObjectsLibrary.Add( obj );
MyObjectsByClassification = from myobjects in App.MyObjectsLibrary
group myobjects by myobjects.Classification into c
orderby c.Key
select new PublicGrouping<string, MyObject>(c);
}
}
Bind MyObjectsByClassification to LongListSelector.ItemsSource in XAML, and make sure you notify the LongListSelector of changes to the property by using INotifyPropertyChanged.
By using LINQ, the object you actually assign to ItemsSource is an IEnumerable<T> not an ObservableCollection<T>. LINQ-to-objects does not support automatic updating via ObservableCollection. After all, it returns a forward-only IEnumerable<T> and not a collection of any kind.
Change your ViewModel to actually expose an ObservableCollection<PublicGrouping<string, MyObject>> and bind your ItemsSource directly to that.