I'm writing a universal windows app and am trying to get my own Context Menu for a TextBox. Everything works as expected in the Store App, but on the Phone App the ContextMenuOpening event isn't firing. I've tried with holding and tapping a selected text, but it isn't working, the only thing that is happening, is the little circle for Copy showing up.
Here's where I register the Event Handler: (the method is called at page loading)
public void FlipViewLoaded()
{
TextBox textBox = GetChildControl<TextBox>
(_imagesFlipView, "ReadOnlyTextBox");
textBox.ContextMenuOpening +=
new ContextMenuOpeningEventHandler(Open);
}
And this is the handler:
private async void Open(object sender, DoubleTappedRoutedEventArgs e)
{
e.Handled = true;
TextBox textbox = (TextBox)sender;
if (textbox.SelectionLength > 0)
{
var menu = new PopupMenu();
menu.Commands.Add(new UICommand("Get Word", null, 1));
menu.Commands.Add(new UICommand("Get Text", null, 2));
var chosenCommand = await menu.ShowAsync(new Point());
if (chosenCommand != null)
{
switch (chosenCommand.Id.ToString())
{
// different commands implementations
}
}
else
{
Debug.WriteLine("The chosen command is null !!");
}
}
else
{
Debug.WriteLine("The selected _text is null !!");
}
}
As I said, it works perfectly in the Store App (the menu shows up when I hold the selected Text or when I right click on it), but the event doesn't even get fired in Phone App.
EDIT Here's the part of the xaml code with the TextBox (the rest is just the standard code that comes with the page + a hub):
<HubSection>
<DataTemplate>
<FlipView x:Name="ImagesFlipView" ItemsSource="{Binding Images}"
viewmodel:ImagesPageViewModel.FlipView="{Binding ElementName=ImagesFlipView}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding ImageURL}" />
<StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Stretch" >
<TextBox x:Name="TranslationTextBox" Visibility="Visible"
Height="80" IsReadOnly="True" TextWrapping="Wrap"
BorderThickness="0" Margin="5"
Style="{StaticResource MyTextBoxStyle}"
Background="{StaticResource TextBoxButtonBackgroundThemeBrush}"
Foreground="White" FontSize="25" VerticalAlignment="Bottom" />
<TextBox x:Name="ReadOnlyTextBox" FontSize="25" IsReadOnly="True"
Height="80" TextWrapping="Wrap" Text="{Binding Path=Translations[english]}"
BorderThickness="0" Foreground="White" Margin="5"
Style="{StaticResource MyTextBoxStyle}"
Background="{StaticResource TextBoxButtonBackgroundThemeBrush}"
VerticalAlignment="Bottom" />
</StackPanel>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</DataTemplate>
</HubSection>
The answer is simple, the TextBox does not have a ContextMenuOpening event in WindowsPhone.
So even if you put that code in an universal apps, it cannot happen.
Universal apps only TRY to match windows 8.1 with windows phone. If an event, or a property is not found, and a correspondance is not found, it is simply ignored.
EDIT: To complete the answer, what you have to do, is to think of another behavior when you are in your windows phone app.
Universal apps projects define pre-processing variables, so you can use code like
#if WINDOWSPHONE
var myWindowsPhoneVar = "windowsPhone";
#else
var myWindowsPhoneVar = "!windowsPhone";
#endif
I'm not quite sure the preprocessing variable for windows phone is exactly "WINDOWSPHONE" but you won't have trouble finding it.
Related
I have an application that displays a datagrid. However the data has gotten big and I want to incorporate filters to some of the rows. I've gotten as far as creating a DataTemplate for my headers:
<DataGrid>
<DataGrid.Resources>
...
<DataTemplate x:Key="HeaderTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding}" VerticalAlignment="Center"/>
<ToggleButton Name="FilterButton" Grid.Column="1" Content="▼" Margin="2, 1, 1, 1" Padding="1, 0"/>
<Popup IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}" PlacementTarget="{Binding ElementName=FilterButton}" StaysOpen="False">
<Border Background="White" Padding="3">
<TextBox Text={Binding PetNameFilterSearchBox, Mode=TwoWay} Width="300"/> <!--The Text Box I want to bind-->
</Border>
</Popup>
</Grid>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Width="6*" Header="Pet Name" Binding="{Binding PetName}" ElementStyle="{DynamicResource DataGridTextColumnWrap}" HeaderTemplate="{StaticResource HeaderTemplate}"/>
</DataGrid.Columns>
</DataGrid>
So far what it does is show a button next to the header text and when you click on it a small popup window appears containing a text box. The desired effect is that the user can type in the text box and data will be filtered according to what was typed.
In my view model I already have my filter text box property that I want to use for binding:
public string PetNameFilterSearchBox
{
get
{
return _petNameFilterSearchBox;
}
set
{
_petNameFilterSearchBox = value;
RaisePropertyChanged(nameof(PetNameFilterSearchBox));
FilterData(); //As you're writing
}
}
private string _petNameFilterSearchBox = string.Empty;
public CollectionView PetDataFilterView { get; set; }
public bool OnFilterTriggered(object item)
{
if (item is AvailablePetInfo petInfo)
{
var pet_name = PetNameFilterSearchBox;
if (pet_name != string.Empty)
return (petInfo.DisplayName.Contains(pet_name));
}
return true;
}
public void FilterData()
{
CollectionViewSource.GetDefaultView(AvailablePetInfo).Refresh();
}
//Constructor
public PetInfoViewModel()
{
AvailablePetInfo = GetPetInfo();//gets the list
ContactFilterView = (CollectionView)CollectionViewSource.GetDefaultView(AvailablePetInfo);
ContactFilterView.Filter = OnFilterTriggered;
}
When I run my code I see the little button next to the header, I click on it and I see the textbox. But when I start typing I dont see my datagrid updating. I set some breakpoints in my PetNameFilterSearchBox and I find that when I start typing it's not getting hit. This tells me that there's something wrong with the binding. Can someone tell me what I'm doing wrong?
Your problem is one of DataContext.
I'll be assuming PetNameFilterSearchBox is a property of the Window hosting the DataGrid and that the appropriate DataContext is set at the Window level.
Normally, DataContext is inherited by child elements, so setting the DataContext for the Window would set it for all its children. But things change once you start using DataTemplates.
In a DataTemplate, the root DataContext is always the data object that's being displayed. In your case, that's the string "Pet Name". This is why you can put <ContentControl Content="{Binding}"/> inside the DataTemplate and have it display "Pet Name".
The downside is you can't put <TextBox Text="{Binding PetNameFilterSearchBox}"/> and expect it to bind to the Window, because that DataContext is being overridden by the DataTemplate.
Normally, you can get around the DataTemplate DataContext problem by using RelativeSource, which you can use walk up the visual tree and find another source to bind to. But this doesn't work inside a Popup because a Popup is not actually part of the Window's visual tree.
What will work is ElementName:
<TextBox Text="{Binding PetNameFilterSearchBox, Mode=TwoWay, ElementName=W}" Width="300"/>
In the above example, I set on my Window Name="W".
I'm building a Windows Phone 8.1 App for a client and have run into something I can't source an answer for, hence the question. I apologize in advance as it's probably something obvious and I'm oblivious to it.
I have a GridView bound to a vendor list from my data model. I can select / click a returned value from the Grid as planned.
XAML extract:
<GridView x:Name="VendorsGridView"
ItemsSource="{Binding}"
Grid.Row="1"
Margin="10,8,10,12"
Foreground="White"
SelectionMode="Single"
IsSwipeEnabled="False"
ItemClick="VendorsGridView_ItemClick"
IsItemClickEnabled="True"
ItemTemplate="{StaticResource VendorTemplate}">
</GridView>
</Grid.RowDefinitions>
<TextBlock Text="{Binding StrVendor}"
Name="VNo"
Grid.Row="0"
Margin="0,0,0,0"
VerticalAlignment="Top"
HorizontalAlignment="Center"
FontSize="18"
FontWeight="SemiBold"/>
<TextBlock Text="{Binding StrVName}"
Name="VName"
Grid.Row="1"
Margin="0,0,0,0"
VerticalAlignment="Center"
TextWrapping="Wrap"
FontSize="14"/>
If I examine e.ClickedItem in the debug window I can see the value I am trying to find, (StrVendor or vendor number). The design is then to write this back to a static table for use as a default when looking at other data.
Debug Window Output:
e.ClickedItem
{MOQ_v301.ViewModel.VendorViewModel}
base: {MOQ_v301.ViewModel.VendorViewModel}
IsDirty: true
isDirty: true
StrVendor: "40520"
strVendor: "40520"
StrVName: "Forest Garden PLC"
strVName: "Forest Garden PLC"
My question is how can I get the vendor number captured to a string variable to achieve it?
Because your grid is bound to a model, you are getting 1 item of that model back through the click. So just cast that item to the model and get the Vender number... Not sure what the actual model class is but assuming it's VendorViewModel the code should be: ((VendorViewModel)e.ClickedItem).StrVendor this will give you the actual vendor number.
Best to check if you are actually getting a model so the final code could be as following:
if(e.ClickedItem is VendorViewModel)
{
var vendornr = ((VendorViewModel)e.ClickedItem).StrVendor;
}
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 Ellipse in my WPF application. I want to change the colour of its outline whenever it is double clicked. I found this (old) tutorial about making this work by using the available MouseDown event and checking for a ClickCount of two in the event handler. This is the simplest solution to my problem and I'd like to try and get this to work before creating an empty button Control Template.
However, I'm unable to find the clicked ellipse in my code behind file. Supposedly this works in the tutorial, but I'm wondering if I'm missing anything.
Here's the code that contains the ellipse. It is the 3rd column of a grid:
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Column="3">
<StackPanel Orientation="Vertical" Margin="3,1" Background="GhostWhite">
<ItemsControl Name="FlowLinkItems" ItemsSource="{Binding FlowLinkList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="40">
<Ellipse Name="FlowLinkEllipse" Stroke="BlueViolet" Height="38" VerticalAlignment="Center" MouseDown="Ellipse_MouseDown"/>
<TextBlock TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Message}"></TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
In the tutorial, the code behind method worked like this:
private void Ellipse_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
FlowLinkEllipse.Stroke = "Red";
}
}
And the error I'm seeing is:
The name 'FlowLinkEllipse' does not exist in the current context
If this method is not possible I'm open to suggestions that are as simple as possible (I'm still new to WPF and the only thing my app will handle is this double click).
Note: I do have this line in my code behind and it works fine.
FlowLinkItems.MouseLeftButtonUp += FlowLinkItems_MouseLeftButtonUp;
As #Magus noted, you can't reference an item from code-behind, that is inside a DataTemplate. That should be no problem here, though: sender will contain a reference to the ellipse:
private void Ellipse_MouseDown(object sender, MouseButtonEventArgs e)
{
if (ellipse as sender == null || e.ClickCount < 2)
return;
var ellipse = (Ellipse)sender;
ellipse.Stroke = System.Windows.Media.Brushes.Red;
}
I am building an app for Windows Phone, and in this app I have a list of Movies with Title, Plot and Picture.
I have this list bound to a ListBox with a custom DataTemplate for the items showing the data. I also created a second page to show the details of each movie.
My problem now is the navigation between these pages. I'm using MVVM to build the applications and most of the approaches I've found searching on internet is to use the OnSelectionChanged event in the code-behind, but it goes agains what I want, that is to use MVVM.
Other approach I've seen, which is the one I'm trying, is to bind the SelectedItem to a property in the ViewModel, but I can't make it change the property, it seems that I cannot select an item in the listbox. Also, I don't have the visual feedback when I press one of the items in my listbox, like the feedback we have in the settings menu of the phone for example.
The code I'm using in the listbox is:
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Movies}" SelectedItem="{Binding SelectedMovieItem}" SelectionMode="Single" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<!--Replace rectangle with image-->
<Rectangle Height="50" Width="50" Fill="#FFE5001b" Margin="12,0,9,0"/>
<StackPanel Width="311">
<TextBlock Text="{Binding Name}" TextWrapping="NoWrap" Style="{StaticResource PhoneTextExtraLargeStyle}" Foreground="#000" />
<!--<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>-->
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Another approach I've seen is to use the INavigationService to achieve this, I found this article: http://windowsphonegeek.com/articles/MVVM-in-real-life-Windows-Phone-applications-Part1
I read the parts one and two, but I couldn't understand this one works.
So, what I want to know is whether the approach I'm using is the correct to make a page navigation, or if there is a better way using MVVM to do this with visual feedback on the listbox.
Why is handling Event in the code behind against MVVM? Handling events interaction is part of the UI. Of course you won't all you code logic there. But you are trying just to go to the next page. I do something like this :
private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (MainListBox.SelectedIndex == -1)
return;
// Navigate to the new page
NavigationService.Navigate(new Uri("/Views/detailsPage.xaml?selectedItem=" + MainListBox.SelectedIndex, UriKind.Relative));
// Reset selected index to -1 (no selection)
MainListBox.SelectedIndex = -1;
}