Why is my Named WPF Shape Inaccesible from Code Behind? - c#

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;
}

Related

Custom Panel with Reorder and animations / transitions

I have a custom class called FluidPanel that extends Panel and overrides methods MeasureOverride and ArrangeOverride. The goal is to create the Google Keep appearence. Ok, it's working fine. (app link)
But, because I'm extending a basic Panel and using it as the ItemsPanelTemplate, I'm missing 2 things: Reorder and some transitions, that simply doens't work out of the box. See code:
<GridView CanReorderItems="True" CanDrag="True" AllowDrop="True">
<GridView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition FromVerticalOffset="200" IsStaggeringEnabled="True"/>
<ReorderThemeTransition/>
</TransitionCollection>
</GridView.ItemContainerTransitions>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:FluidPanel/><!--custom panel = reorder doesn't work-->
<!--<StackPanel/>--><!--reorder and animations work normally (reorder to see)-->
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<Grid Width="50" Height="50" Background="Red"/>
<Grid Width="50" Height="50" Background="Green"/>
<Grid Width="50" Height="50" Background="Blue"/>
<Grid Width="50" Height="50" Background="Orange"/>
<Grid Width="50" Height="50" Background="Purple"/>
<Grid Width="50" Height="50" Background="Pink"/>
</GridView>
So, the main question is: How to create a custom Panel with Reorder fully working, including animations? (like that offset to the left/right/...)
A second (less important) question is: And with the EntranceThemeTransition working?
I partially found the solution.
Unfortunately it's not as easy as it should be.
For custom Panels, it seems that we have to implement the Reorder manually, listening to the drag & drop events.
Here is an article about it: Extending GridView with Drag and Drop
and here is a simplified code about it.
The reorder animation is added by manually changing the Visual State:
private void OnDragOver(object sender, DragEventArgs e)
{
var item = (e.OriginalSource as FrameworkElement).DataContext as Note;
if (item == null) return;
e.Data.Properties["targetItem"] = item;
var itemContainer = (sender as ItemsControl).ContainerFromItem(item) as Control;
if (itemContainer == null) return;
VisualStateManager.GoToState(itemContainer, "BottomReorderHint", true);
}
But I still hope there is any easier way to do it, giving the fact that a lot of Panels implement it (StackPanel, ItemsWrapGrid, ...).
Still can't get the EntranceThemeTransition to work on the custom panel.
EDIT: workaround to make EntranceThemeTransition works

TextBox.ContextMenuOpening not firing in Windows Phone 8.1 App

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.

Preventing Parent From Firing Events When Child MouseDown

I have a Grid placed at the top of the Window in which inside of it there's an Image placed. The Grid is supposedly dragging the window with a MouseDown event.
However, whenever i want to fire a MouseDown event to the Child Image it doesn't work but, instead it fires the Grid's.
private void toggleTbr_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
private void leapTcb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
//my code
}
As you see i tried e.Handled = true; but it changes nothing, then i thought of trying of using PreviewMouseLeftButtonDown instead of MouseLeftButtonDown but, still the same.
What am i doing wrong here, or how to prevent the Grid from triggering?
XAML:
<Grid x:Name="toggleTbr" MouseLeftButtonDown="toggleTbr_MouseLeftButtonDown">
<Grid x:Name="leapTcb_" Height="21" Width="26">
<Image x:Name="leapTcb" MouseLeftButtonDown="leapTcb_MouseLeftButtonDown">
<Image.Background>
<ImageBrush Source="Resources/leap_1.png"/>
</Image.Background>
</Image>
</Grid>
</Grid>
Your Code works fine, but if it isn't enough you can try using this:
IsHitTestVisible="True"
The Image element has no Background property, instead, set the Source property directly at the image element.
<Image x:Name="leapTcb" Source="Resources/leap_1.png" MouseLeftButtonDown="leapTcb_MouseLeftButtonDown"/>
However you made this running, but with the specified change it behaves like you want, at least on my machine.
Use this this is working my side
<Grid x:Name="toggleTbr" MouseLeftButtonDown="toggleTbr_MouseLeftButtonDown" Background="Red">
<Grid x:Name="leapTcb_" Height="21" Width="26">
<Image x:Name="leapTcb" PreviewMouseLeftButtonDown="leapTcb_MouseLeftButtonDown">
<Image.Background>
<ImageBrush Source="Resources/leap_1.png"/>
</Image.Background>
</Image>
</Grid>
</Grid>

Change Application Resource Property in Code Behind

I have a user control in Silverlight (Form.xaml) that uses labels to show data. Currently I have the foreground color and visibility of these labels controlled by a template in app.xaml as follows:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
x:Class="TestSilverlight.App"
>
<Application.Resources>
<ControlTemplate x:Key="DataLabel" x:Name="DataLabel" TargetType="sdk:Label">
<sdk:Label Visibility="Visible" Foreground="White" Content="{TemplateBinding Content}"></sdk:Label>
</ControlTemplate>
</Application.Resources>
</Application>
And here is the xaml for the label in Form.xaml:
<sdk:Label Template="{StaticResource DataLabel}" HorizontalAlignment="Left" Margin="140,53,0,0" VerticalAlignment="Top" Content="Ground" FontSize="13.333" Width="138"/>
When I click on the edit button of Form.xaml, I'd like to hide these labels. However, I'm cannot figure out how to change the visibility property in the code behind for this template.
private void EditButton_Click(object sender, RoutedEventArgs e)
{
// Place code to alter template properties here...
}
Any ideas on how to do this? Thank you so much for your help and input.
You could try something like (works using WPF):
<ControlTemplate x:Key="DataLabel" x:Name="DataLabel" TargetType="sdk:Label">
<sdk:Label x:Name="myLabelTemplate" Visibility="Visible" Foreground="White" Content="{TemplateBinding Content}"></sdk:Label>
</ControlTemplate>
(I just gave a name to the label inside the controlTemplate)
<sdk:Label x:Name="myLabel" Template="{StaticResource DataLabel}" HorizontalAlignment="Left" Margin="140,53,0,0" VerticalAlignment="Top" Content="Ground" FontSize="13.333" Width="138"/>
(I just gave a name to the label inside the xaml)
var res = (FindResource("DataLabel") as ControlTemplate).FindName("myLabelTemplate", myLabel);
if (res != null && res is FrameworkElement)
(res as FrameworkElement).Visibility = Visibility.Hidden;
I didn't check to see if FindResource return something not null, and so on (I think you can handle it ;) )
However If I were you I wouldn't use the app resource to put a particular resource of a user control (i'd use the template it in the xaml of the userControl (as an attached resource) instead or even wouldn't use a template at all if you want to modify properties within: it could lead to crash the app because of null pointer exception if not well managed)

Drag Event Won't Fire for ListBox in Silverlight

Hopefully this is an easy question. I'm using the ListBoxDragDropTarget from the Silverlight Toolkit to set up drag and drop from one ListBox to another. I can't seem to get the event to fire. Here's my XAML code:
<toolkit:ListBoxDragDropTarget HorizontalAlignment="Left"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Top"
VerticalContentAlignment="Stretch"
Margin="39,117,0,0"
Grid.Row="1"
AllowDrop='True'>
<ListBox x:Name='columnHeadings'
MinHeight='100'
MinWidth='100'>
</ListBox>
</toolkit:ListBoxDragDropTarget>
<toolkit:ListBoxDragDropTarget AllowDrop='True'
Grid.Column='1'
Grid.Row='1'
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
VerticalAlignment="Center"
HorizontalAlignment="Left">
<ListBox x:Name='customerFields'
Grid.Column='1'
Grid.Row='1'
Visibility='Collapsed'
Drop='CustomerFieldsDrop'>
</ListBox>
</toolkit:ListBoxDragDropTarget>
And here's my event handler in the code behind page:
private void CustomerFieldsDrop(object sender, DragEventArgs e)
{
MessageBox.Show(string.Format("Something was dropped!"));
}
As you can see, I was aiming for something real simple. I tried assigning an event handler to the parent ListBoxDragDropTarget for the customerFields List Box; ironically, that worked.
My purpose here is to allow a user to import a text file and get a listing of the file's column headers in one List Box and then "connect" them to data fields listed in the second List Box. So no list reordering or moving items from one list to another.
The columnHeadings.ItemsSource property is a string[] object. The customerFields.ItemsSource property is an IEnumerable<string> object.
Any insight would be appreciated.
I think the AllowDrop="True" and Drop="EventName" properties need to be within the same element to work. You probably have to set the AllowDrop property to "True" in the ListBox itself:
<ListBox x:Name="customerFields"
Grid.Column="1"
Grid.Row="1"
Visibility="Collapsed"
Drop="CustomerFieldsDrop"
AllowDrop="True"
</ListBox>
Or add the Drop="CustomerFieldsDrop" property to the ListBoxDragDropTarget tag:
<toolkit:ListBoxDragDropTarget AllowDrop='True'
Grid.Column='1'
Grid.Row='1'
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Drop="CustomerFieldsDrop">
Either one should work...

Categories