how to set Listpicker items where SelectionMode is multiple - c#

In my WP8 app, i am using the ListPicker control with multi selection option. In my page, i am loading the Listpicker data from a List of custom classes. And i can able to save what objects are user selected based by implementing the SummaryForSelectedItemsDelegate event and i am saving this info to Isolated storage for later access.
My main problem, how to select the above user selected option when user opened this page where this list picker is there?
I tried using the SelectionChanged event and try to select the object based on stored data, it didn't worked.
<toolkit:ListPicker x:Name="userCountryList" ItemsSource="{Binding CountryList}" Header="Choose a country or region:" SelectionMode="Multiple" FullModeItemTemplate="{StaticResource DataTemplate2}" />
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="DataTemplate2">
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" FontSize="28" TextWrapping="Wrap" Text="{Binding CountryName}" VerticalAlignment="Center" Width="Auto"/>
</StackPanel>
</DataTemplate>
Code behind:
var brushes = new List<CustomClass>();
brushes.Add(new CustomClass { CountryCode = "US", CountryName = "United States" });
brushes.Add(new CustomClass { CountryCode = "FR", CountryName = "France" });
brushes.Add(new CustomClass { CountryCode = "DE", CountryName = "Germany" });
brushes.Add(new CustomClass { CountryCode = "CA", CountryName = "Canada" });
userCountryList.SummaryForSelectedItemsDelegate = SummarizeItems;
userCountryList.ItemsSource = brushes;
private string SummarizeItems(IList items)
{
if (items != null && items.Count > 0)
{
string summarizedString = "";
if (items != null)
for (int i = 0; i < items.Count; i++)
{
summarizedString += ((CustomClass )items[i]).CountryCode;
// If not last item, add a comma to seperate them
if (i != items.Count - 1)
summarizedString += ", ";
}
if (!AppSettings.Default.UserSelectedMarkets.Equals(summarizedString))
AppSettings.Default.UserSelectedMarkets = summarizedString;
return summarizedString;
}
else
return "Nothing selected";
}

In your page, override OnNavigatedTo and add all objects to userCountryList.SelectedItems:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
foreach (var o in GetSelectedObjects())
{
userCountryList.SelectedItems.Add(o);
}
base.OnNavigatedTo(e);
}

Related

Combobox is not selecting the value that has bound from the code xaml

<ComboBox x:Name="Designator"
ItemsSource="{Binding ActiveDesignators}"
DisplayMemberPath="Code"
SelectedValuePath="Code"
SelectedItem="{Binding SelectedUserSearch.Designator,
Converter={StaticResource entityConverter},
ConverterParameter=ActiveDesignators,
Mode=TwoWay}"
Margin="5,0"
Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Center">
<i:Interaction.Behaviors>
<behaviours:SelectorRapidAccessKeyBehavior RapidAccessPropertyName="Code" />
<behaviours:MouseWheelScrollBehaviour />
</i:Interaction.Behaviors>
</ComboBox>
ViewModel:
public FindViewModel (ActiveDesignators activeDesignators,)
{
this.ActiveDesignators = activeDesignators;
this.userService.GetAllUserSearchAsync(this.OnUserSearchLoaded);
}
private void OnUserSearchLoaded(object sender, ServiceEventArgs<IEnumerable<UserSearch>> eea)
{
if (eea.ReturnValue != null)
{
this.currentUserCollection = new EntityCollection<UserSearch>(eea.ReturnValue.Where(u => u.UserId == this.userId));
var collection = new EntityCollection<UserSearch>();
collection.AddRange(this.currentUserCollection.Select(lu => lu.Clone()).Cast<UserSearch>().OrderBy(r => r.Name));
collection.Add(new UserSearch() { Id = -1, Name = WaterMarkAddNewSearch, UserId = this.userId });
this.UserSearchCollection = new EntityCollection<UserSearch>(collection);
this.SelectedUserSearch = this.SetDefaultSearchIfMentioned();
}
}
Data is filling up in the combobox. However selected item is not selecting by default in combobox.
Please help me out why it is not binding selected item value.

Dynamic rows and columns in DataGrid and for each cell write from a WPF control

I'm new to WPF and I'm trying to create a DataGrid with 4 columns defined "Ticket information", "Name", "Email" and "Zip Code". What I do is the following:
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("Info Tickets");
table.Columns.Add("Name");
table.Columns.Add("Email");
table.Columns.Add("ZipCode");
Later I intend to generate rows automatically depending on a number given by the user, I keep this amount in a variable and use it in a cycle to generate the rows in this way:
int quantity = (int)Application.Current.Resources["NumPeopleQuantity"];
for (int i = 0; i < quantity; i++)
{
// Create row
System.Data.DataRow row = table.NewRow();
row["Info Tickets"] = i + 1;
row["Name"] = "";
row["Email"] = "";
row["ZipCode"] = "";
// Insert the row
table.Rows.Add(row);
}
In the end I relate the table to the Data grid that I created as follows:
Grid1.ItemsSource = ((System.ComponentModel.IListSource)table).GetList();
This works correctly and the desired columns and rows are added to the DataGrid. So far everything perfect, I can write a name, email and zip code for each row from the keyboard of my computer, when the information has been filled correctly I have a button that retrieves all the content of the dataGrid and assigns it to a model to manipulate it In code, I do it as follows:
System.Data.DataView data = (System.Data.DataView)Grid1.ItemsSource;
var f = (PaymentViewModel)DataContext;
string expresion;
expresion = "\\w+([-+.']\\w+)*#\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
for (int i = 0; i < data.Count; i++)
{
obj = new DataContactTicket
{
CustomerName = data.Table.Rows[i]["Name"].ToString(),
CustomerEmail = data.Table.Rows[i]["Email"].ToString(),
CustomerZip = data.Table.Rows[i]["ZipCode"].ToString()
};
if (obj.CustomerName == "" || obj.CustomerEmail == "" || obj.CustomerZip == "")
{
f.Mensaje = "Ticket information fields cannot be empty";
return;
}
else
{
if (Regex.IsMatch(obj.CustomerEmail, expresion))
{
if (Regex.Replace(obj.CustomerEmail, expresion, String.Empty).Length == 0)
{
names.Add(obj);
}
else
{
return;
}
}
else
{
f.Mensaje = "Please validate the email format";
return;
}
}
}
f.Grid1 = names;
I make the corresponding validations and assign them to a list in my ViewModel, everything is correct, the problem I have is that I need the user to type this information from an onScreenKeyboard and not from the keyboard of a computer for textboxes is easy , the reference looks like this:
<TextBox x:Name="TxtMail" Height="auto" Width="500" FontSize="24" FontWeight="Bold" TextChanged="TxtMail_TextChanged"
Text="{Binding Text, ElementName=onScreenKeyboard}"/>
<Grid HorizontalAlignment="Stretch" Margin="114,-208,-114,208">
<StackPanel HorizontalAlignment="Left" Margin="-132,240,0,-240">
<TermControls:OnScreenKeyboard x:Name="onScreenKeyboard" HorizontalContentAlignment="Stretch" VerticalAlignment="Bottom" VerticalContentAlignment="Bottom" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="4" />
</StackPanel>
The idea is that for each cell of the dataGrid that the user selects, he can also write through the control in it, I have not found a way to do this. I hope you can help me, thank you very much.

C# ListView How to create ContextMenu programatically

I have this code behind :
private void InitializeListView()
{
//RAZ
lv.Items.Clear();
GridView gridView = new GridView();
gridView.AllowsColumnReorder = true;
GridViewColumn gvc1 = new GridViewColumn();
gvc1.DisplayMemberBinding = new System.Windows.Data.Binding("SN");
gvc1.Header = "SN";
GridViewColumn gvc2 = new GridViewColumn();
gvc2.DisplayMemberBinding = new System.Windows.Data.Binding("a1");
gvc2.Header = "A1";
gridView.Columns.Add(gvc2);
GridViewColumn gvc3 = new GridViewColumn();
gvc3.DisplayMemberBinding = new System.Windows.Data.Binding("a2");
gvc3.Header = "A2";
gridView.Columns.Add(gvc3);
for (int i = 0; i < lv.Count; i++)
{
this.lv.Items.Add(
new dataToUse
{
sn= tab[i][0],
a1= tab[i][1],
a2 = tab[i][2]
});
}
this.lv.View = gridView;
}
in order to generate dinamycally this :
<ListView x:Name="lv" HorizontalAlignment="Left" Height="360" Margin="305,192,0,0" VerticalAlignment="Top" Width="607" SelectionMode="Extended" >
<ListView.View >
<GridView AllowsColumnReorder="true">
<GridViewColumn DisplayMemberBinding="{Binding sn}" >
<GridViewColumnHeader>
<GridViewColumnHeader.ContextMenu>
<ContextMenu>
<MenuItem Header="Asc"/>
<MenuItem Header="Desc" />
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding a1}">
<GridViewColumnHeader >
<GridViewColumnHeader.ContextMenu>
<ContextMenu >
<MenuItem Header="Asc" />
<MenuItem Header="Desc" />
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding a2}">
<GridViewColumnHeader >
<GridViewColumnHeader.ContextMenu>
<ContextMenu >
<MenuItem Header="Asc" />
<MenuItem Header="Desc"/>
</ContextMenu>
</GridViewColumnHeader.ContextMenu>
</GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
The problem is that when I generate the project, I cannot see the ContextMenu (and so the MenuItems)
I already use this kind of code in another project, but here, it doesn t work...
I guess the code behind is the last one wich is generated, so if you could explain me how to create a ContextMenu programatically. Could be good.
Could you help me please ?
Thanks !
Here is an example for the A2 column. The others follow the same approach.
// Remove:
//gvc3.Header = "A2";
// Replace by:
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
new MenuItem() { Header="Asc"},
new MenuItem() { Header="Desc"}
}
}
};
In order to implement the actual sorting with possibility to sort by multiple columns, the menu items could be created with the following helper functions:
private MenuItem CreateAscendingSortMenuItem(string prop)
{
var result = new MenuItem() { Header = "Asc" };
result.Click += (s, e) =>
{
var toRemove = lv.Items.SortDescriptions.Where(x => x.PropertyName == prop).ToList();
foreach (var item in toRemove)
{
lv.Items.SortDescriptions.Remove(item);
}
lv.Items.SortDescriptions.Insert(0, new SortDescription(prop, ListSortDirection.Ascending));
};
return result;
}
private MenuItem CreateDescendingSortMenuItem(string prop)
{
var result = new MenuItem() { Header = "Desc" };
result.Click += (s, e) =>
{
var toRemove = lv.Items.SortDescriptions.Where(x => x.PropertyName == prop).ToList();
foreach (var item in toRemove)
{
lv.Items.SortDescriptions.Remove(item);
}
lv.Items.SortDescriptions.Insert(0, new SortDescription(prop, ListSortDirection.Descending));
};
return result;
}
Then just create the items using the helper function instead of calling the constructor directly.
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
CreateAscendingSortMenuItem("a2"),
CreateDescendingSortMenuItem("a2")
}
}
};
Thanks grek40 !
In addtion to your answer (how to create an event for a MenuItem):
// Remove:
//gvc3.Header = "A2";
// Replace by:
MenuItem item1 = New MenuItem();
item1.Header = "Desc";
//Event
item1+= new RoutedEventHandler(this.someFunction_click);
gvc3.Header = new GridViewColumnHeader()
{
Content = "A2",
ContextMenu = new ContextMenu()
{
Items =
{
new MenuItem() { Header="Asc"},
item1
}
}
};
//Function launched by the event
private void someFunction_Click(object sender, System.EventArgs e)
{
//do something
}
Thank you guys for your help !!!

Windows Phone C# Iterate through ListView child controls

I'm having a problem with a ListView for Windows Phone:
I'm using a databinding to display all items in a folder, but when I try to iterate through them, I don't get a control, but the class I use to get the items in the LocalFolder of the app (The subjectpicker class)!
SubjectPicker class:
class SubjectPicker {
public static async Task<List<SubjectPicker>> SubjectData() {
List<string> Names = new List<string>();
List<Brush> Colors = new List<Brush>();
List<string> Items = new List<string>();
List<List<TestOrTask>> TestsAndTasks = new List<List<TestOrTask>>();
StorageFolder LocalFolder = ApplicationData.Current.LocalFolder;
var files = await LocalFolder.GetFilesAsync();
foreach (var file in files) {
//await file.DeleteAsync();
List<TestOrTask> TAT = new List<TestOrTask>();
Names.Add(file.DisplayName);
bool readItems = false;
var contents = await FileIO.ReadLinesAsync(file);
foreach (var content in contents) {
if (content.Contains("Subject Color")) {
string colorname = content.Replace("Subject Color: ", "");
Colors.Add(ColorConverter.fromString_Brush(colorname));
}
else if (content == "<Items>") readItems = true;
else if (content == "</Items>") readItems = false;
if (readItems == true && content != "") {
// Layout: <Name>: <Score>/<Maximum>|<YYYY>/<MM>/<DD>
string name = content.Split(':')[0];
string Score = content.Split(':')[1].Replace(" ", "");
string Date = content.Split('|')[1];
TestOrTask TOT = new TestOrTask(
name,
double.Parse(Score.Split('/')[0]),
double.Parse(Score.Split('/')[1]),
new DateTime(
Int32.Parse(Date.Split('/')[0]),
Int32.Parse(Date.Split('/')[1]),
Int32.Parse(Date.Split('/')[2])));
TAT.Add(TOT);
}
}
Items.Add("Aantal Testen & Taken: " + TAT.Count.ToString());
TestsAndTasks.Add(TAT);
}
var data = new List<SubjectPicker>();
for (int i = 0; i < Names.Count; i++) {
data.Add(new SubjectPicker(Names[i], Colors[i], Items[i], TestsAndTasks[i]));
}
return data;
}
public SubjectPicker(string name, Brush color, string itemstotal, List<TestOrTask> TestsAndTasks) {
PickerName = name;
PickerColor = color;
ItemTotal = itemstotal;
this.TestsAndTasks = TestsAndTasks;
}
public string PickerName { get; set; }
public Brush PickerColor { get; set; }
public string ItemTotal { get; set; }
public List<TestOrTask> TestsAndTasks = new List<TestOrTask>();
}
Xaml Code:
<Page.Resources>
<DataTemplate x:Key="SubjectTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Margin="0,9.5,0,0" Background="Transparent" >
<Rectangle Height="50" Width="50" Fill="{Binding PickerColor}" RadiusX="5" RadiusY="5"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding PickerName}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
<TextBlock Text="{Binding ItemTotal}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar x:Name="AppBar" Visibility="Collapsed">
<AppBarButton x:Name="EditSubject" Icon="Edit" Label="Aanpassen" Click="EditSubject_Click"/>
<AppBarButton x:Name="DeleteSubject" Icon="Delete" Label="Verwijderen" Click="DeleteSubject_Click"/>
</CommandBar>
</Page.BottomAppBar>
<Grid x:Name="MainGrid" Loaded="MainGrid_Loaded">
<Controls:TopBarControl x:Name="TopBarControl" Margin="0" VerticalAlignment="Top" PageName="Vakken" ControlsVisible="All" Width="Auto" BackButtonClicked="TopBar_BackButtonClicked" AddButtonClicked="TopBar_AddButtonClicked" EditButtonClicked="TopBar_EditButtonClicked"/>
<Grid x:Name="ControlsGrid" Margin="0,50,0,-60" Tapped="ControlsGrid_Tapped">
<ListView x:Name="SubjectList" ItemsSource="{Binding}" ItemTemplate="{StaticResource SubjectTemplate}"/>
</Grid>
</Grid>
Void to iterate through:
private async Task SelectSubjects() {
for (int i = 0; i < SubjectList.Items.Count; i++) {
var control = SubjectList.Items[i];
Grid subject = control as Grid;
if (subject != null) {
subject.Background = new SolidColorBrush(SchoolToolsColors.AppColor);
await Task.Delay(TimeSpan.FromMilliseconds(50));
}
}
isSelecting = true;
AppBarVisible = Visibility.Visible;
}
Thanks in advance!!!
When iterating on databinded control you'll always get its underlying data.
You should Style.Triggers to alter UI based on data (changing background, showing/hiding controls, etc.).
However, there is a way to go with altering UI from C# but that would make XAML and code-behind tightly coupled => that introduces more complexity into your code - simply believe me, it is not what you want/need.

Create Hyperlink in TextBlock via Binding

My problem is to find the urls from the text content and convert it into the clickable hyperlinks via data binding.
This is what I've tried
<TextBlock Tag="{Binding message}" x:Name="postDescription" TextWrapping="Wrap"
Grid.Row="3" Grid.ColumnSpan="3" Margin="10,10,10,12" FontSize="16"
TextAlignment="Justify" Foreground="{StaticResource foreGroundWhite}" >
<Run Text="{Binding description, Converter={StaticResource statusFormatter}}" />
</TextBlock>
In code,
public class StatusFormatter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return returnTextWithUrl((String)value);
}
public static String returnTextWithUrl(String text)
{
if(text == null) { return null; }
MatchCollection mactches = uriFindRegex.Matches(text);
foreach (Match match in mactches)
{
//Need Help here
HyperlinkButton hyperlink = new HyperlinkButton();
hyperlink.Content = match.Value;
hyperlink.NavigateUri = new Uri(match.Value);
text = text.Replace(match.Value, ??);
}
return text;
}
}
}
The output should be something like this
<TextBlock Tag="{Binding message}" x:Name="postDescription" TextWrapping="Wrap"
Grid.Row="3" Grid.ColumnSpan="3" Margin="10,10,10,12" FontSize="16"
TextAlignment="Justify" Foreground="{StaticResource foreGroundWhite}" >
Click this link -
<Hyperlink NavigateUri="http://www.bing.com">bing</Hyperlink>
- for more info.
</TextBlock>
Any Help?
To do what you want you will have to use Inlines property of your TextBlock, but as it's not a DependencyProperty, it cannot be a target of binding. We will have to extend your TextBlock class, but as it's sealed we will have to use other class.
Lets define static class, which will add apropriate Inline - Hyperlink or Run, depending on Regex match. It can look for example like this:
public static class TextBlockExtension
{
public static string GetFormattedText(DependencyObject obj)
{ return (string)obj.GetValue(FormattedTextProperty); }
public static void SetFormattedText(DependencyObject obj, string value)
{ obj.SetValue(FormattedTextProperty, value); }
public static readonly DependencyProperty FormattedTextProperty =
DependencyProperty.Register("FormattedText", typeof(string), typeof(TextBlockExtension),
new PropertyMetadata(string.Empty, (sender, e) =>
{
string text = e.NewValue as string;
var textBl = sender as TextBlock;
if (textBl != null)
{
textBl.Inlines.Clear();
Regex regx = new Regex(#"(http://[^\s]+)", RegexOptions.IgnoreCase);
var str = regx.Split(text);
for (int i = 0; i < str.Length; i++)
if (i % 2 == 0)
textBl.Inlines.Add(new Run { Text = str[i] });
else
{
Hyperlink link = new Hyperlink { NavigateUri = new Uri(str[i]), Foreground = Application.Current.Resources["PhoneAccentBrush"] as SolidColorBrush };
link.Inlines.Add(new Run { Text = str[i] });
textBl.Inlines.Add(link);
}
}
}));
}
Then in XAML we use it just like this:
<TextBlock local:TextBlockExtension.FormattedText="{Binding MyText}" FontSize="15"/>
And after putting some text to my property:
private void firstBtn_Click(object sender, RoutedEventArgs e)
{
MyText = #"Simple text with http://mywebsite.com link";
}
I can see such a result:
I stumbled on this post while looking for the same for UWP. In case you are here too for the same, I'd recommend you use a HyperlinkButton instead of a Hyperlink wrapped in a Textblock. Below is the code on how to use it.
<HyperlinkButton Content="{x:Bind Text}" NavigateUri="{x:Bind Hyperlink}"/>
You can also use Binding instead of x:Bind and yes you can set the Mode=OneWay too.
Read More on Microsoft Docs
You can't put Hyperlink objects inside a String. Instead you need to return a Span containing inlines from your converter. The plain text will be Run objects and the links will be Hyperlink objects.
public static Span returnTextWithUrl(String text)
{
if(text == null) { return null; }
var span = new Span();
MatchCollection mactches = uriFindRegex.Matches(text);
int lastIndex = 0;
foreach (Match match in mactches)
{
var run = new Run(text.Substring(lastIndex, match.Index - lastIndex));
span.Inlines.Add(run);
lastIndex = match.Index + match.Length;
var hyperlink = new Hyperlink();
hyperlink.Content = match.Value;
hyperlink.NavigateUri = new Uri(match.Value);
span.Inlines.Add(hyperlink);
}
span.Inlines.Add(new Run(text.Substring(lastIndex)));
return span;
}

Categories

Resources